¿Existe una alternativa a string.Replace que no distinga entre mayúsculas y minúsculas?

Resuelto Aheho asked hace 15 años • 16 respuestas

Necesito buscar una cadena y reemplazar todas las apariciones de %FirstName%y %PolicyAmount%con un valor extraído de una base de datos. El problema es que las mayúsculas de FirstName varían. Eso me impide utilizar el String.Replace()método. He visto páginas web sobre el tema que sugieren

Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);

Sin embargo, por alguna razón, cuando intento reemplazarlo %PolicyAmount%con $0, el reemplazo nunca se realiza. Supongo que tiene algo que ver con que el signo de dólar sea un carácter reservado en la expresión regular.

¿Existe otro método que pueda utilizar que no implique desinfectar la entrada para tratar con caracteres especiales de expresiones regulares?

Aheho avatar Oct 29 '08 02:10 Aheho
Aceptado

Parece que string.Replace debería haber una sobrecarga que requiera una StringComparisondiscusión. Como no es así, puedes intentar algo como esto:

public static string ReplaceString(string str, string oldValue, string newValue, StringComparison comparison)
{
    StringBuilder sb = new StringBuilder();

    int previousIndex = 0;
    int index = str.IndexOf(oldValue, comparison);
    while (index != -1)
    {
        sb.Append(str.Substring(previousIndex, index - previousIndex));
        sb.Append(newValue);
        index += oldValue.Length;

        previousIndex = index;
        index = str.IndexOf(oldValue, index, comparison);
    }
    sb.Append(str.Substring(previousIndex));

    return sb.ToString();
}
C. Dragon 76 avatar Oct 28 '2008 21:10 C. Dragon 76

Desde MSDN
$0 - "Sustituye la última subcadena que coincide con el número de grupo (decimal)".

En .NET, el grupo de expresiones regulares 0 es siempre la coincidencia completa. Por un $ literal necesitas

string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase);
Todd White avatar Oct 28 '2008 19:10 Todd White

Es un grupo de respuestas algo confuso, en parte porque el título de la pregunta es en realidad mucho más grande que la pregunta específica que se hace. Después de leerlo, no estoy seguro de que alguna respuesta esté a algunas ediciones de asimilar todas las cosas buenas aquí, así que pensé en intentar resumir.

Aquí hay un método de extensión que creo que evita los errores mencionados aquí y proporciona la solución más aplicable.

public static string ReplaceCaseInsensitiveFind(this string str, string findMe,
    string newValue)
{
    return Regex.Replace(str,
        Regex.Escape(findMe),
        Regex.Replace(newValue, "\\$[0-9]+", @"$$$0"),
        RegexOptions.IgnoreCase);
}

Entonces...

  • Este es un método de extensión @MarkRobinson
  • Esto no intenta omitir Regex @Helge (realmente tienes que hacerlo byte por byte si quieres olfatear cadenas como esta fuera de Regex)
  • Pasa el excelente caso de prueba de @MichaelLiu , "œ".ReplaceCaseInsensitiveFind("oe", "")aunque es posible que haya tenido en mente un comportamiento ligeramente diferente.

Desafortunadamente, el comentario de @HA de que tienes que hacer Escapelos tres no es correcto . El valor inicial y newValueno es necesario que lo sea.

Nota: Sin embargo, debe colocar $caracteres de escape en el nuevo valor que está insertando si son parte de lo que parecería ser un marcador de "valor capturado" . De ahí los tres signos de dólar en Regex.Replace dentro de Regex.Replace [sic]. Sin eso, algo como esto se rompe...

"This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")

Aquí está el error:

An unhandled exception of type 'System.ArgumentException' occurred in System.dll

Additional information: parsing "The\hisr\ is\ he\HISr\ fork,\ he\hIsr\ spoon,\ he\hisrsssssss\ knife\." - Unrecognized escape sequence \h.

Te diré una cosa, sé que las personas que se sienten cómodas con Regex sienten que su uso evita errores, pero a menudo todavía soy partidario de detectar cadenas de bytes (pero solo después de haber leído a Spolsky sobre codificaciones ) para estar absolutamente seguro de que estás obteniendo lo que necesitas. destinado a casos de uso importantes. Me recuerda un poco a Crockford sobre " expresiones regulares inseguras ". Con demasiada frecuencia escribimos expresiones regulares que permiten lo que queremos (si tenemos suerte), pero sin querer permitimos más entrada (por ejemplo, ¿Es $10realmente una cadena de "valor de captura" válida en mi expresión regular newValue, arriba?) porque no fuimos lo suficientemente reflexivos. . Ambos métodos tienen valor y ambos fomentan diferentes tipos de errores no intencionales. A menudo es fácil subestimar la complejidad.

Ese escape extraño $(y que Regex.Escapeno escapó a los patrones de valores capturados como $0hubiera esperado en los valores de reemplazo) me volvió loco por un tiempo. Programar es difícil (c) 1842

ruffin avatar Jul 04 '2014 20:07 ruffin

Parece que el método más sencillo es simplemente utilizar el método Reemplazar que viene con .Net y existe desde .Net 1.0:

string res = Microsoft.VisualBasic.Strings.Replace(res, 
                                   "%PolicyAmount%", 
                                   "$0", 
                                   Compare: Microsoft.VisualBasic.CompareMethod.Text);

Para utilizar este método, debe agregar una referencia al ensamblado Microsoft.VisualBasic. Este ensamblado es una parte estándar del tiempo de ejecución de .Net, no es una descarga adicional ni está marcado como obsoleto.

CleverPatrick avatar Aug 23 '2010 19:08 CleverPatrick