web-dev-qa-db-fra.com

C # - Le moyen le plus simple de supprimer la première occurrence d'une sous-chaîne d'une autre chaîne

Je dois supprimer la première (et UNIQUEMENT la première) occurrence d'une chaîne d'une autre chaîne.

Voici un exemple remplaçant la chaîne "\\Iteration". Ce:

 NomProjet \\ Itération \\ Version1 \\ Itération1 

deviendrait ceci:

 NomProjet \\ Version1 \\ Itération1 

Voici du code qui fait ceci:

const string removeString = "\\Iteration";
int index = sourceString.IndexOf(removeString);
int length = removeString.Length;
String startOfString = sourceString.Substring(0, index);
String endOfString = sourceString.Substring(index + length);
String cleanPath = startOfString + endOfString;

Cela semble beaucoup de code. 

Ma question est donc la suivante: existe-t-il un moyen plus propre/plus lisible/plus concis de procéder?

64
Vaccano
int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
    ? sourceString
    : sourceString.Remove(index, removeString.Length);
119
LukeH
string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length);

EDIT: @OregonGhost a raison. Je diviserais moi-même le script avec des conditionnels pour vérifier une telle occurrence, mais je partais du principe que les chaînes étaient censées appartenir les unes aux autres par certaines exigences. Il est possible que les règles de traitement des exceptions imposées par l'entreprise exigent cette possibilité. J'utiliserais moi-même quelques lignes supplémentaires pour effectuer des vérifications conditionnelles et également pour les rendre un peu plus lisibles pour les développeurs débutants, qui risquent de ne pas prendre le temps de les lire suffisamment.

24
Joel Etherton
sourceString.Replace(removeString, "");
11
malcolm waldron

Écrit un test rapide TDD pour cette

    [TestMethod]
    public void Test()
    {
        var input = @"ProjectName\Iteration\Release1\Iteration1";
        var pattern = @"\\Iteration";

        var rgx = new Regex(pattern);
        var result = rgx.Replace(input, "", 1);

        Assert.IsTrue(result.Equals(@"ProjectName\Release1\Iteration1"));
    }

rgx.Replace (input, "", 1); dit de regarder dans l'entrée tout ce qui correspond au motif, avec "", 1 fois.

10
CaffGeek

Vous pouvez utiliser une méthode extension pour le plaisir. En général, je ne recommande pas d'associer des méthodes d'extension à une classe aussi générale que string, mais comme je l'ai dit, c'est amusant. J'ai emprunté la réponse de @ Luke car il ne sert à rien de réinventer la roue.

[Test]
public void Should_remove_first_occurrance_of_string() {

    var source = "ProjectName\\Iteration\\Release1\\Iteration1";

    Assert.That(
        source.RemoveFirst("\\Iteration"),
        Is.EqualTo("ProjectName\\Release1\\Iteration1"));
}

public static class StringExtensions {
    public static string RemoveFirst(this string source, string remove) {
        int index = source.IndexOf(remove);
        return (index < 0)
            ? source
            : source.Remove(index, remove.Length);
    }
}
6
Mike Valenty

Je suis tout à fait d’accord pour dire que c’est parfait pour une méthode d’extension, mais je pense que cela peut être un peu amélioré.

public static string Remove(this string source, string remove,  int firstN)
    {
        if(firstN <= 0 || string.IsNullOrEmpty(source) || string.IsNullOrEmpty(remove))
        {
            return source;
        }
        int index = source.IndexOf(remove);
        return index < 0 ? source : source.Remove(index, remove.Length).Remove(remove, --firstN);
    }

Cela fait un peu de récursion qui est toujours amusant.

Voici également un test unitaire simple:

   [TestMethod()]
    public void RemoveTwiceTest()
    {
        string source = "look up look up look it up";
        string remove = "look";
        int firstN = 2;
        string expected = " up  up look it up";
        string actual;
        actual = source.Remove(remove, firstN);
        Assert.AreEqual(expected, actual);

    }
2
Greg Roberts

Si vous souhaitez une méthode simple pour résoudre ce problème. (Peut être utilisé comme une extension)

Voir ci-dessous: 

    public static string RemoveFirstInstanceOfString(this string value, string removeString)
    {
        int index = value.IndexOf(removeString, StringComparison.Ordinal);
        return index < 0 ? value : value.Remove(index, removeString.Length);
    }

Usage: 

    string valueWithPipes = "| 1 | 2 | 3";
    string valueWithoutFirstpipe = valueWithPipes.RemoveFirstInstanceOfString("|");
    //Output, valueWithoutFirstpipe = " 1 | 2 | 3";

Inspiré par et modifié les réponses de @ LukeH et @ Mike.

N'oubliez pas le StringComparison.Ordinal pour éviter les problèmes avec les paramètres Culture https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html

0
Daniel Filipe