2010-02-04 17 views
54

Necesito eliminar la primera (y SOLO la primera) ocurrencia de una cadena de otra cadena.C# - La manera más sencilla de eliminar la primera aparición de una subcadena de otra cadena

Aquí hay un ejemplo que reemplaza la cadena "\\Iteration". Este:

 
ProjectName\\Iteration\\Release1\\Iteration1 

se convertiría en esto:

 
ProjectName\\Release1\\Iteration1 

Aquí algo de código que hace esto:

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; 

Eso parece como una gran cantidad de código.

Así que mi pregunta es esta: ¿hay una manera más clara/más legible/más concisa para hacer esto?

Respuesta

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

Esta respuesta puede fallar para cadenas que involucren caracteres que no sean ASCII. Por ejemplo, bajo la cultura en-US, 'æ' y' ae' se consideran iguales. Intentar eliminar 'paedia' de' Encyclopædia' arrojará una 'ArgumentOutOfRangeException', ya que está intentando eliminar 6 caracteres cuando la subcadena coincidente solo contiene 5. – Douglas

+1

Podemos modificarlo de esta manera:' sourceString.IndexOf (removeString, StringComparison. Ordinal) 'para evitar la excepción. –

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

EDIT: @OregonGhost is right. Yo mismo rompería el guión con condicionales para verificar si ocurría algo así, pero estaba operando bajo la suposición de que los hilos se debían pertenecer unos a otros por algún requisito. Es posible que se espere que las reglas de manejo de excepciones requeridas por el negocio atrapen esta posibilidad. Yo mismo utilizaría un par de líneas adicionales para realizar comprobaciones condicionales y también para que sea un poco más legible para los desarrolladores junior que no se toman el tiempo para leerlo lo suficiente.

+6

Esto bloqueará si removeString no está contenida en Cadena origen. – OregonGhost

10

Escrito una prueba de TDD rápida para este

[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 (entrada, "", 1); dice buscar en la entrada cualquier cosa que coincida con el patrón, con "", 1 vez.

+2

Al igual que usted resolvió el problema. Solo considere el rendimiento cuando use expresiones regulares para un problema como este. – Thomas

6

Puede usar un método de extensión por diversión. Por lo general, no recomiendo adjuntar métodos de extensión a una clase de propósito general como la cadena, pero como dije, esto es divertido. Tomé prestada la respuesta de @ Luke porque no tiene sentido reinventar la rueda.

[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

¿Por qué normalmente no recomienda adjuntar métodos de extensión a una clase de propósito general como String? ¿Qué desventajas aparentes hay para esto? –

2

Definitivamente estoy de acuerdo en que esto es perfecto para un método de extensión, pero creo que se puede mejorar un poco.

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

Esto hace un poco de recursividad que siempre es divertido.

Aquí es una prueba de unidad simple también:

[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 que "* [r] crea una nueva cadena en la que todos las ocurrencias de una cadena especificada en la instancia actual se reemplazan por otra cadena especificada * ". El OP quería reemplazar la ** primera ** ocurrencia. –

+2

Además, debe explicar su respuesta un poco ya que las respuestas de solo código no son aceptables. Eche un vistazo a las otras respuestas y compárelas con las suyas para obtener algunos consejos. –

Cuestiones relacionadas