Necesito buscar una cadena de texto y reemplazar todas las apariciones de %FirstName% y %PolicyAmount% con un valor sacados de una base de datos. El problema es la capitalización de Nombre varía. Que me impide el uso de la 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 me pruebe y reemplace %PolicyAmount% con $0, la sustitución tiene lugar nunca. Supongo que tiene algo que ver con el signo de dólar ser un carácter reservado en regex.

Hay otro método puedo usar que no se trata de desinfectar la entrada a lidiar con regex caracteres especiales?

  • Si «$0» es la variable en la que no afecta la expresión regular en todo.
InformationsquelleAutor Aheho | 2008-10-28

15 Comentarios

  1. 128

    De MSDN

    $0 – «Sustituye a la última subcadena coincidente por el número de grupo (número de decimales).»

    En .NET expresiones Regulares grupo 0 es siempre todo el partido. Para un $ literal que usted necesita para

    string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase);
    • en este caso particular, este está muy bien, pero en los casos donde las cadenas son de entrada desde el exterior, uno no puede estar seguro de que no contienen caracteres que significan algo especial en las expresiones regulares
    • Debes escapar los caracteres especiales como este: string valor = Regex.Replace(«%PolicyAmount%», Regex.De Escape(«%PolicyAmount%»), Regex.De Escape(«$0»), RegexOptions.IgnoreCase);
    • En realidad regex-escapando de la segunda cadena no tendrá ningún efecto, aparte de conseguir un extra \ antes de la sustitución. Ignorar los caracteres especiales en la cadena de reemplazo, es mejor escribir un matchevaluator que devuelve la cadena en sí.
    • Por favor tenga cuidado al usar Regex.De Escape en la Expresión regular.Reemplace. Tendrás que escapar de todas de las tres cadenas de pasar y llame Regex.Unescape en el resultado!
    • De acuerdo a msdn: «el escape de Caracteres son reconocidos en los patrones de expresión regular, pero no en los modelos de reemplazo.» ( msdn.microsoft.com/en-us/library/4edbef7e.aspx )
    • hm, yo no conseguir tu comentario. «Regex.Replace(«a[b]b», Regex.De Escape(«]B»), Regex.De Escape («] «C»), RegexOptions.IgnoreCase)» devuelve una[b]C, como se esperaba. Puede usted explicar por qué usted piensa que uno necesita para escapar de la entrada y unescape después?
    • Es mejor usar: string valor = Regex.Replace(«%PolicyAmount%», Regex.De Escape(«%PolicyAmount%»), «$0».Reemplazar(«$», «$$»), RegexOptions.IgnoreCase); como reemplazo reconoce solo dolar de los signos.

  2. 294

    Parece string.Replace debe tienen una sobrecarga que lleva un StringComparison argumento. Como no es así, usted podría 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();
    }
    • Los métodos de extensión solo funciona en 3+ a la derecha? +1 a Todos los mismos, ya que el OP no era específico, pero se pueden mencionar
    • Además, este será más rápido que el regex.
    • De niza. Me gustaría cambiar ReplaceString a Replace.
    • De acuerdo con los comentarios anteriores. Esto puede ser hecho en un método de extensión con el mismo nombre de método. Simplemente pop en una clase estática con la firma de método: public static string Replace(esta Cadena str, cadena de oldValue, cadena de newValue, StringComparison comparación)
    • La velocidad no lo es todo. El uso de la expresión regular en lugar de hacerlo usted mismo, introducir una complejidad adicional y, potencialmente, también errores. Además, el regex solución es mucho más fácil de leer y de mantener.
    • en general, eso puede estar bien, pero tengo que tomar arbitraria de las cadenas del usuario y no puede arriesgarse a la entrada significativas para regex. Por supuesto, supongo que podría escribir un bucle y poner una barra invertida delante de cada uno y de cada personaje… En ese momento, que bien podría hacer lo anterior (en mi humilde opinión).
    • Estoy de acuerdo en el uso de esta solución en su lugar, pero sólo en caso de que usted necesite, puede usar Regex.De Escape escapar expresiones de personajes importantes para usted.
    • Hmm, interesante-no sabía acerca de Escape(). Gracias.
    • Mientras que la unidad de prueba de esto me encontré en el caso de que nunca iba a regresar cuando oldValue == newValue == "".
    • Para el caso de oldValue = «», de la Cadena.Reemplazar no lo permite. He añadido excepción de los cheques para que coincida con la Cadena.Reemplazar excepciones: if (oldValue == null) { throw new ArgumentNullException("oldValue"); } if (oldValue == "") { throw new ArgumentException("String cannot be of zero length.", "oldValue"); }
    • Un gran trabajo aquí. Me convirtió en un método de extensión, pero lo que es más importante, he añadido un rápido vistazo en la parte superior en el caso de que str no contiene oldValue. Solo tiene que mover el int index = str.IndexOf(oldValue, comparison); a la primera línea del método y volver str si index == -1
    • Wha debe hacer sobre el desempeño de la stackoverflow.com/a/13847351/206730 ?
    • Este es el buggy; ReplaceString("œ", "oe", "", StringComparison.InvariantCulture) lanza ArgumentOutOfRangeException.
    • Acaba de enterarse de Regex, mantener el código limpio. Este es un ejemplo trivial, pero todavía se ve muy complicado. La gente está obsesionada acerca de la velocidad y, a continuación, la escritura sirve un código como este, es lamentable.
    • tener que escapar de la cadena de reemplazo por defecto no se ve como el código limpio para mí. También estoy seguro de que el real Regex la aplicación en sí misma se ve más complicada y, probablemente, tenía numerosos errores en sus versiones iniciales. Espero un final libre de bugs de la versión que está publicado.
    • Puedo usar regex ampliamente y no hay bugs que he notado. Usted es mucho más probable que introducir un error con código personalizado como este.
    • El uso de StringBuilder de esta manera no va a mejorar el rendimiento de la forma en que desea; será inicializado con un 16 búfer de caracteres y el bucle podría causar un número de asignaciones de memoria y de las copias. Usted debe iniciar su StringBuilder a una capacidad adecuada antes de comenzar a concatenar cadenas a ella.
    • ¿Qué piensa usted de if(oldValue.Length > str.Length) return str; … Cualquier materia extraña que esto podría causar. He escrito un par de pruebas, todos están utilizando OrdinalIgnoreCase y que la solución no rompe ninguna. Yo puede ser que falten algunos casos, por supuesto, así que ¿qué te parece?
    • Aquí están las pruebas para este Reemplazar gist.github.com/Galilyou/00dcd0dab2d2a050c30c
    • El problema que he señalado, no es con la comprobación de la longitud; el problema es con IndexOf y StringComparison.InvariantCulture.
    • nota: ReplaceString("","","",StringComparison.CurrentCulture) dará lugar a un bucle infinito!
    • Así que con su rápida salida de evitar que se ejecuta el StringBuilder sino introducir un if declaración? Parece un micro-optimización (si) para mí.
    • No es sólo el constructor, pero la copia de cadena después de que el while() y, a continuación, el .ToString de vuelta a una cadena así. Estas cosas suman. Pero más importante que eso, hay el desarrollador beneficio de ver rápidamente qué sucede si no hay ninguna coincidencia. Por CIERTO, verificación de MS código para verificaciones similares, el hacer rápido-salida comprueba así.

  3. 43

    Tipo de un confuso grupo de respuestas, en parte debido a que el título de la pregunta en realidad es mucho más grande que la pregunta específica que se pide. Después de leer esto, no estoy seguro de que cualquier respuesta es un par de ediciones de distancia a partir de la asimilación de todas las cosas buenas aquí, así que pensé en probar a suma.

    He aquí un método de extensión que creo que evita los escollos que se mencionan aquí y proporciona la más ampliamente aplicable solución.

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

    Así que…

    Por desgracia, @HA ‘s comentario que usted tiene a de Escape los tres no es correcto. El valor inicial y newValue no es necesario.

    Nota: sin embargo, Usted tiene que escapar $s en el nuevo valor que desea insertar si son parte de lo que parece ser una «captura valor» marcador. Así, los tres signos de dólar en el Regex.Reemplazar dentro de la Expresión regular.Reemplace [sic]. Sin eso, algo como esto 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.

    Decirle lo que, conozco gente que se sienta cómodo con Regex sentir que su uso evita errores, pero estoy a menudo aún parciales, byte oler cadenas (pero sólo después de haber leído Spolsky en las codificaciones de) para estar absolutamente seguro de que usted está consiguiendo lo que pretende importante de casos de uso. Me recuerda a Crockford en «inseguro de expresiones regulares» un poco. Demasiado a menudo nos escriben regex que permitir que lo que queremos (si tenemos suerte), pero sin querer permitir más (por ejemplo, Es $10 realmente válida «captura de valor» la cadena en mi newValue regexp, de arriba?) porque no estábamos reflexiva suficiente. Ambos métodos tienen valor, y tanto alentar a los diferentes tipos de errores involuntarios. A menudo es fácil subestimar la complejidad.

    Que raro $ escapar (y que Regex.Escape no escapar capturado valor patrones como $0 como yo habría esperado en los valores de sustitución) me volvía loco por un tiempo. La programación Es Duro (c) 1842

    • Realmente merece más votos. Además de 1842, lol. 🙂
  4. 30

    He aquí un método de extensión. No estás seguro de dónde lo he encontrado.

    public static class StringExtensions
    {
        public static string Replace(this string originalString, string oldValue, string newValue, StringComparison comparisonType)
        {
            int startIndex = 0;
            while (true)
            {
                startIndex = originalString.IndexOf(oldValue, startIndex, comparisonType);
                if (startIndex == -1)
                    break;
    
                originalString = originalString.Substring(0, startIndex) + newValue + originalString.Substring(startIndex + oldValue.Length);
    
                startIndex += newValue.Length;
            }
    
            return originalString;
        }
    
    }
    • ¿Qué hay acerca de stackoverflow.com/a/244933/206730 ? cual es la mejor manera ?
    • Usted puede necesitar para controlar vacío/string nulo de los casos.
    • Mutiple errores en esta solución: 1. Compruebe originalString, oldValue y newValue el valor null. 2. No dar orginalString de nuevo (no de trabajo, los tipos simples no son pasados por referencia), pero asignar el valor de orginalValue primero a una cadena nueva y modificar y dar de nuevo.
  5. 30

    Parece el método más fácil es simplemente usar el método de reemplazo que se incluye con .Net y ha sido de alrededor desde entonces .Net 1.0:

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

    Con el fin de utilizar este método, usted tiene que agregar una Referencia a Microsoft.VisualBasic assemblly. Esta asamblea es una parte estándar de la .Net, no es una descarga extra o marcado como obsoleto.

    • Funciona. Usted necesita agregar una referencia a Microsoft.VisualBasic asamblea.
    • Extraño que este método tiene algunos problemas cuando la he usado (los personajes al comienzo de la línea de desaparecidos). La respuesta más popular aquí de C. Dragon 76 funcionado como se esperaba.
    • El problema con esto es que devuelve una NUEVA cadena, incluso si el reemplazo no está hecho, donde la cadena.replace( ) devuelve un puntero a la misma cadena. Puede obtener ineficiente si estás haciendo algo como una carta de forma de mezcla.
    • Brain2000, usted está equivocado. Todas las cuerdas .NET son inmutables.
    • Der_Meister, mientras que lo que dices es correcto, y que no lo Brain2000 dijo mal.
  6. 10
        ///<summary>
        ///A case insenstive replace function.
        ///</summary>
        ///<param name="originalString">The string to examine.(HayStack)</param>
        ///<param name="oldValue">The value to replace.(Needle)</param>
        ///<param name="newValue">The new value to be inserted</param>
        ///<returns>A string</returns>
        public static string CaseInsenstiveReplace(string originalString, string oldValue, string newValue)
        {
            Regex regEx = new Regex(oldValue,
               RegexOptions.IgnoreCase | RegexOptions.Multiline);
            return regEx.Replace(originalString, newValue);
        }
  7. 8

    Inspirado por cfeduke la respuesta, he hecho esta función que utiliza IndexOf para encontrar el valor anterior en la cadena y, a continuación, reemplaza con el nuevo valor. He utilizado este en una secuencia de comandos de SSIS el procesamiento de millones de filas, y el regex-método de manera más lenta que esta.

    public static string ReplaceCaseInsensitive(this string str, string oldValue, string newValue)
    {
        int prevPos = 0;
        string retval = str;
        //find the first occurence of oldValue
        int pos = retval.IndexOf(oldValue, StringComparison.InvariantCultureIgnoreCase);
    
        while (pos > -1)
        {
            //remove oldValue from the string
            retval = retval.Remove(pos, oldValue.Length);
    
            //insert newValue in it's place
            retval = retval.Insert(pos, newValue);
    
            //check if oldValue is found further down
            prevPos = pos + newValue.Length;
            pos = retval.IndexOf(oldValue, prevPos, StringComparison.InvariantCultureIgnoreCase);
        }
    
        return retval;
    }
    • +1 por no usar regex cuando no es necesario. Asegúrese de que, el uso de un par de líneas de código, pero es mucho más eficiente que basado en expresiones regulares reemplazar a menos que necesite el $ funcionalidad.
  8. 6

    Expansión en C. Dragón 76‘s respuesta popular al hacer que su código en una extensión que sobrecarga el valor predeterminado Replace método.

    public static class StringExtensions
    {
        public static string Replace(this 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();
         }
    }
  9. 3

    Basado en Jeff Reddy respuesta, con algunas optimizaciones y validaciones:

    public static string Replace(string str, string oldValue, string newValue, StringComparison comparison)
    {
        if (oldValue == null)
            throw new ArgumentNullException("oldValue");
        if (oldValue.Length == 0)
            throw new ArgumentException("String cannot be of zero length.", "oldValue");
    
        StringBuilder sb = null;
    
        int startIndex = 0;
        int foundIndex = str.IndexOf(oldValue, comparison);
        while (foundIndex != -1)
        {
            if (sb == null)
                sb = new StringBuilder(str.Length + (newValue != null ? Math.Max(0, 5 * (newValue.Length - oldValue.Length)) : 0));
            sb.Append(str, startIndex, foundIndex - startIndex);
            sb.Append(newValue);
    
            startIndex = foundIndex + oldValue.Length;
            foundIndex = str.IndexOf(oldValue, startIndex, comparison);
        }
    
        if (startIndex == 0)
            return str;
        sb.Append(str, startIndex, str.Length - startIndex);
        return sb.ToString();
    }
  10. 2

    una versión similar a C. del Dragón, pero por si solo necesitas una sustitución:

    int n = myText.IndexOf(oldValue, System.StringComparison.InvariantCultureIgnoreCase);
    if (n >= 0)
    {
        myText = myText.Substring(0, n)
            + newValue
            + myText.Substring(n + oldValue.Length);
    }
    • Esto no funcionará si usted necesita para reemplazar varias coincidencias
  11. 1

    Aquí es otra opción para la ejecución de Regex reemplazos, ya que muchas personas no parecen darse cuenta de que los partidos contener la ubicación dentro de la cadena:

        public static string ReplaceCaseInsensative( this string s, string oldValue, string newValue ) {
            var sb = new StringBuilder(s);
            int offset = oldValue.Length - newValue.Length;
            int matchNo = 0;
            foreach (Match match in Regex.Matches(s, Regex.Escape(oldValue), RegexOptions.IgnoreCase))
            {
                sb.Remove(match.Index - (offset * matchNo), match.Length).Insert(match.Index - (offset * matchNo), newValue);
                matchNo++;
            }
            return sb.ToString();
        }
    • Podría usted explicar por qué estás multiplicando por MatchNo?
    • Si hay una diferencia en la longitud entre el oldValue y newValue, la cadena va a conseguir más o menos como se reemplazan los valores. partido.El índice se refiere a la ubicación original dentro de la cadena, tenemos que ajustar para que las posiciones de movimiento debido a la sustitución. Otro enfoque sería para ejecutar el Quitar/Insertar de derecha a izquierda.
    • Yo entiendo eso. Eso es lo que el «offset» variable. Lo que yo no entiendo es por qué se están multiplicando por matchNo. Mi intuición me dice que la ubicación de un partido dentro de una cadena no tendría relación con el recuento de sucesos previos.
    • No importa, voy a conseguir ahora. Las necesidades de desplazamiento de ser escalado basado en el número de ocurrencias. Si usted está perdiendo 2 caracteres cada vez que usted necesita para hacer un reemplazo, debe tener en cuenta que el cómputo de los parámetros para el método de quitar
  12. 0
    Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase);
    • Esto no funciona. El $ no es el token. Es en el strReplace Con cadena.
    • Y no se puede adaptar para que?
    • Este sitio se supone que es un repositorio para las respuestas correctas. No las respuestas que son casi correcta.
  13. 0

    La expresión regular método debería funcionar. Sin embargo lo que también puedes hacer es inferior en el caso de la cadena a partir de la base de datos, menor caso el %variables% de lo que tienen, y, a continuación, busque las posiciones y longitudes en la parte inferior con grafía de la cadena a partir de la base de datos. Recuerde, las posiciones en una cadena que no cambian sólo porque su menor entubado.

    A continuación, utilizar un bucle que va en sentido inverso (es más fácil, si no tendrá que mantener un recuento de donde más tarde los puntos mover a) eliminar de tu no-inferior con grafía de la cadena a partir de la base de datos de la %variables% por su posición y longitud e insertar los valores de reemplazo.

    • Por la inversa, me refiero a que el proceso de las ubicaciones encontradas en el reverso de más lejos a más corto, de no atravesar la cadena a partir de la base de datos a la inversa.
    • Usted puede, o podría simplemente utilizar el Regex 🙂
  14. 0

    (Ya que todo el mundo está teniendo una oportunidad en esto). Aquí está mi versión (con el valor de los cheques, y de la correcta entrada y la sustitución de escape) ** Inspirado de todo el internet y otras versiones:

    using System;
    using System.Text.RegularExpressions;
    
    public static class MyExtensions {
        public static string ReplaceIgnoreCase(this string search, string find, string replace) {
            return Regex.Replace(search ?? "", Regex.Escape(find ?? ""), (replace ?? "").Replace("$", "$$"), RegexOptions.IgnoreCase);          
        }
    }

    Uso:

    var result = "This is a test".ReplaceIgnoreCase("IS", "was");
  15. 0

    Déjame hacer mi caso y, a continuación, usted puede rasgar me a pedazos si te gusta.

    Regex no es la respuesta para este problema – demasiado lento y la memoria hambre, relativamente hablando.

    StringBuilder es mucho mejor que la cadena de destrozarlo.

    Ya que este será un método de extensión para complementar string.Replace, creo que es importante para que coincida con cómo funciona – por lo tanto lanzar excepciones para el mismo argumento de los problemas es importante, ya que devuelve la cadena original si el reemplazo no fue hecho.

    Creo que tener un StringComparison parámetro no es una buena idea.
    Yo hice la prueba pero el caso de prueba originalmente mencionado por michael-liu mostraron un problema:-

    [TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]

    Mientras IndexOf coinciden, hay una discrepancia entre la longitud de la coincidencia en la cadena de origen (1) y oldValue.Longitud (2). Esto se manifiesta causando IndexOutOfRange en algunas otras soluciones cuando oldValue.De longitud, fue agregado a la coincidencia actual posición y no he podido encontrar una forma de evitar esto.
    Regex no coincide con el caso de todos modos, así que me tomé la solución pragmática de utilizar sólo StringComparison.OrdinalIgnoreCase mi solución.

    Mi código es similar al de otras respuestas, pero mi giro es que busco un partido antes de ir a la molestia de crear un StringBuilder. Si no se encuentra ninguno, a continuación, potencialmente grande de asignación es evitado. A continuación, el código se convierte en un do{...}while en lugar de un while{...}

    He hecho algunas pruebas extensas en contra de otras Respuestas y este salió marginalmente más rápido y usa un poco menos de memoria.

        public static string ReplaceCaseInsensitive(this string str, string oldValue, string newValue)
        {
            if (str == null) throw new ArgumentNullException(nameof(str));
            if (oldValue == null) throw new ArgumentNullException(nameof(oldValue));
            if (oldValue.Length == 0) throw new ArgumentException("String cannot be of zero length.", nameof(oldValue));
    
            var position = str.IndexOf(oldValue, 0, StringComparison.OrdinalIgnoreCase);
            if (position == -1) return str;
    
            var sb = new StringBuilder(str.Length);
    
            var lastPosition = 0;
    
            do
            {
                sb.Append(str, lastPosition, position - lastPosition);
    
                sb.Append(newValue);
    
            } while ((position = str.IndexOf(oldValue, lastPosition = position + oldValue.Length, StringComparison.OrdinalIgnoreCase)) != -1);
    
            sb.Append(str, lastPosition, str.Length - lastPosition);
    
            return sb.ToString();
        }

Dejar respuesta

Please enter your comment!
Please enter your name here