2012-02-13 28 views
8

Me pregunto cuál es la forma más fácil de reemplazar una cadena de caracteres que debe reemplazarse posteriormente.Reemplazar los caracteres incorrectos de una Cadena con caracteres incorrectos

Por ejemplo:

var str = "[Hello World]"; 
//enclose all occurences of [ and ] with brackets[] 
str = str.Replace("[","[[]").Replace("]","[]]"); 
  • El resultado deseado: [[]Hello World[]]
  • El resultado real: [[[]]Hello World[]]

La razón es, obviamente, la segunda reemplazar en la cuerda ya modificado.

Entonces, ¿cómo reemplazar todas las apariciones de caracteres "malos" con caracteres que contienen caracteres "malos"?


una medición rápida de todos los enfoques reveló que el StringBuilder es la forma más eficiente.

archivo de 190kb (todo en milisegundos)

regexTime   40.5065 
    replaceTime   20.8891 
    stringBuilderTime 6.9776 

archivo 7 MB

regexTime   1209.3529   
    replaceTime   403.3985 
    stringBuilderTime 175.2583 

Por cierto, el StringBuilder enfoque directo de John fue dos veces rápido como el Aggregate enfoque de Sehe.

que he hecho una extensión de ella:

public static String EncloseChars(this string input, char[] charsToEnclose, String leftSide, String rightSide) { 
    if (charsToEnclose == null || leftSide == null || rightSide == null) 
     throw new ArgumentException("Invalid arguments for EncloseChars", charsToEnclose == null ? "charsToEnclose" : leftSide == null ? "leftSide" : "rightSide"); 
    Array.Sort(charsToEnclose); 
    StringBuilder sb = new StringBuilder(); 
    foreach (char c in input) { 
     if (Array.BinarySearch(charsToEnclose, c) > -1) 
      sb.Append(leftSide).Append(c).Append(rightSide); 
     else 
      sb.Append(c); 
    } 
    return sb.ToString(); 
} 

"[Hello World]".EncloseChars(new char[]{'[', ']'},"[","]"); 
+3

+1 Bien medido, Tim. –

Respuesta

5

Aquí hay una muy descoolonada manera de hacerlo. Pero tiene la ventaja de ser bastante cercano a prueba de tontos, creo, y no usar expresiones regulares (en caso de que prefiera no usar expresiones regulares).

StringBuilder sb = new StringBuilder(); 
foreach (char c in str.ToCharArray()) { 
    if (c == '[' || c == ']') { 
     sb.Append('[' + c + ']'); 
    } 
    else { 
     sb.Append(c); 
    } 
} 
string result = sb.ToString(); 
+0

Gracias. A menudo, la forma no cool es la mejor/más rápida. No hay problema cuando está oculto en un método de extensión;) –

4

¿Qué hay de:

str = str.Replace("[", "$1[$2") 
     .Replace("]", "$1]$2") 
     .Replace("$1", "[") 
     .Replace("$2", "]"); 
+2

Buena idea, usando valores de monitor como intermediarios. – Oded

+4

Pero debe verificar si la cadena aún no contiene estos valores de monitor, o lo mismo ocurre nuevamente. Ejemplo: 'Hola [$ 1]' – Oliver

+0

La edición para reemplazar los valores del monitor + los caracteres reales antes de reemplazar los valores de los caracteres reales puede solucionar el problema de Oliver (aunque en una especie de camino de paredes y escalas), pero a costa de la legibilidad , Creo. –

1

¿Qué tal:

char[] replacedChars = str.SelectMany(ch => 
            (ch == '[' ? new char[] {'[', '[', ']'} : 
            (ch == ']' ? new char[] {'[', ']', ']'} : 
            new char[] {ch}))).ToArray(); 
string replaced = new string(replacedChars); 

Tenga en cuenta que esto evita el problema de múltiples bucles, pero crea al menos tantas matrices como caracteres en la cadena de entrada, por lo que podría no ser óptima en términos de rendimiento.

+0

+1 Crear el uso de LINQ. No muy eficiente ... :) – sehe

3

¿Qué pasa con este elegante enfoque de expresión regular: Prueba

Regex.Replace("[Hello World]", @"[\[\]]", "[$0]"); 

Unidad de ella?

[TestMethod] 
public void UnitTestThat() 
{ 
    Assert.AreEqual(@"[[]Hello World[]]", Regex.Replace("[Hello World]", @"[\[\]]", "[$0]")); 
} 

prueba superada


Editar @JohnMcGrant

Aquí es una versión ligeramente menos ineficiente de su código, que tiene, por cierto, es exactamente el mismo comportamiento que la expresión regular anterior:

string result = input.Aggregate(new StringBuilder(), (a, c) => 
    -1 != "[]".IndexOf(c) ? a.AppendFormat("[{0}]", c) : a.Append(c)).ToString(); 
+0

Probablemente sea seguro suponer que esto no sucedería, pero ¿qué pasaría si el texto entre corchetes pudiera contener legítimamente corchetes, tal vez escapado de alguna manera? ¿Eso no rompería la expresión regular? –

+0

@JohnMGant: No, porque eso significa que los requisitos han cambiado. ¿Qué pasa si la pregunta es diferente? ¿Eso rompería la respuesta? Nop. – sehe

+0

Se agregó un enfoque alternativo basado en la versión de @ JohnMGant. Creo que la expresión regular sigue siendo el mejor enfoque :) – sehe

1
StringBuilder result = new StringBuilder(); 

    foreach (Char singleCharacter in str) 
    { 
     result.Append(singleCharacter.Equals('[') ? "[[]" : singleCharacter.Equals(']') ? "[]]" : singleCharacter.ToString()); 
    } 

    str = result.ToString(); 
0

Tenía exactamente el mismo problema, así que hice una función auxiliar para hacer eso

protected string ReplaceUsingDictionary(string subject, Dictionary<string,string> pairs) 
    { 
     StringBuilder sb = new StringBuilder(subject); 

     sb.Replace("{", "{{").Replace("}", "}}"); 

     int i=0; 
     foreach (string key in pairs.Keys.ToArray()) 
     { 
      sb.Replace(
       key.Replace("{", "{{").Replace("}", "}}"), 
       "{" + i + "}" 
      ); 

      i++; 
     } 

     return string.Format(sb.ToString(), pairs.Values.ToArray()); 
    } 

// usage 
Dictionary<string, string> replacements = new Dictionary<string, string>(); 
replacements["["] = "[[]"; 
replacements["]"] = "[]]"; 

string mystr = ReplaceWithDictionary("[HelloWorld]", replacements); // returns [[]HelloWorld[]] 
Cuestiones relacionadas