2010-02-04 16 views
54

Ho bisogno di rimuovere la prima (e SOLO la prima) occorrenza di una stringa da un'altra stringa.C# - Il modo più semplice per rimuovere la prima occorrenza di una sottostringa da un'altra stringa

Ecco un esempio che sostituisce la stringa "\\Iteration". Questo:

 
ProjectName\\Iteration\\Release1\\Iteration1 

sarebbe diventato questo:

 
ProjectName\\Release1\\Iteration1 

Ecco un codice che fa questo:

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; 

che sembra un sacco di codice.

Quindi la mia domanda è questa: c'è un modo più pulito/più leggibile/più conciso per farlo?

risposta

106
int index = sourceString.IndexOf(removeString); 
string cleanPath = (index < 0) 
    ? sourceString 
    : sourceString.Remove(index, removeString.Length); 
+8

Questa risposta potrebbe interrompersi per stringhe che coinvolgono caratteri non ASCII. Ad esempio, sotto la cultura en-US, 'æ' e' ae' sono considerati uguali. Il tentativo di rimuovere 'paedia' da' Encyclopædia' genererà un 'ArgumentOutOfRangeException', poiché stai tentando di rimuovere 6 caratteri quando la sottostringa corrispondente contiene solo 5. – Douglas

+1

Possiamo modificarlo in questo modo:' sourceString.IndexOf (removeString, StringComparison. Ordinale) 'per evitare l'eccezione. –

23
string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length); 

MODIFICA: @OregonGhost ha ragione. Io stesso avrei infranto la sceneggiatura con i condizionali per verificare la presenza di un tale evento, ma stavo operando partendo dal presupposto che le stringhe fossero date per appartenere l'una all'altra da qualche requisito. È possibile che le regole di gestione delle eccezioni richieste dal business prevedano questa possibilità. Io stesso userei un paio di linee extra per eseguire i controlli condizionali e anche per renderlo un po 'più leggibile per gli sviluppatori junior che potrebbero non prendersi il tempo per leggerlo abbastanza a fondo.

+6

Questo andrà in crash se removeString non è contenuta in stringaOrigine. – OregonGhost

10

Ha scritto un test TDD rapida per questo

[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 (ingresso, "", 1); dice di cercare input per qualsiasi cosa corrisponda al modello, con "", 1 volta.

+2

Così hai risolto il problema. Prendi in considerazione le prestazioni quando usi regex per un problema come questo. – Thomas

6

È possibile utilizzare un metodo di estensione per divertimento. In genere, non è consigliabile collegare i metodi di estensione a una classe generica come la stringa, ma come ho detto è divertente. Ho preso in prestito la risposta di Luke poiché non ha senso reinventare la ruota.

[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); 
    } 
} 
+0

Perché in genere non si consiglia di allegare i metodi di estensione a una classe generica come String? Quali aspetti negativi ci sono per questo? –

2

Sono assolutamente d'accordo che questo è perfetto per un metodo di estensione, ma penso che può essere migliorato un po '.

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); 
    } 

Questo fa un po 'di ricorsione che è sempre divertente.

Ecco un semplice test di unità così:

[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); 

    } 
12
sourceString.Replace(removeString, ""); 
+7

[String.Replace] (https://msdn.microsoft.com/en-us/library/fk49wtc1%28v=vs.110%29.aspx) dice che "* [r] crea una nuova stringa in cui tutti le occorrenze di una stringa specificata nell'istanza corrente vengono sostituite con un'altra stringa * * specificata. L'OP voleva sostituire la ** prima ** ricorrenza. –

+2

Inoltre, dovresti spiegare un po 'la tua risposta in quanto le risposte al solo codice non sono accettabili. Dai un'occhiata alle altre risposte e confrontale con le tue per alcuni suggerimenti. –

Problemi correlati