Necesito buscar una cadena y reemplazar todas las ocurrencias de %FirstName%
y %PolicyAmount%
con un valor extraído de una base de datos. El problema es que la capitalización de FirstName varía. Eso me impide usar 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 y reemplazar %PolicyAmount%
con $0
, la sustitución no se lleva a cabo. Supongo que tiene algo que ver con que el signo de dólar sea un carácter reservado en regex.
¿Hay otro método que pueda usar que no implique desinfectar la entrada para tratar con caracteres especiales regex?
Respuestas:
Desde MSDN
$ 0 - "Sustituye la última subcadena que coincide con el número de número de grupo (decimal)".
En .NET Expresiones regulares, el grupo 0 es siempre la coincidencia completa. Por un $ literal necesitas
fuente
Parece que
string.Replace
debería tener una sobrecarga que requiere unStringComparison
argumento. Como no es así, puedes probar algo como esto:fuente
ReplaceString
aReplace
.oldValue == newValue == ""
.ReplaceString("œ", "oe", "", StringComparison.InvariantCulture)
lanzaArgumentOutOfRangeException
.Una especie de grupo confuso de respuestas, 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 unas pocas ediciones de asimilar todas las cosas buenas aquí, así que pensé que trataría de sumar.
Aquí hay un método de extensión que creo que evita las trampas mencionadas aquí y proporciona la solución más ampliamente aplicable.
Entonces...
"œ".ReplaceCaseInsensitiveFind("oe", "")
aunque él pudo haber tenido un comportamiento ligeramente diferente en mente.Desafortunadamente, el comentario de @HA de que tienes que hacer
Escape
las tres cosas no es correcto . El valor inicial ynewValue
no necesita ser.Nota: Sin embargo, debe escapar de
$
s en el nuevo valor que está insertando si son parte de lo que parece ser un marcador de "valor capturado" . Así, los tres signos de dólar en Regex.Replace dentro de Regex.Replace [sic]. Sin eso, algo así se rompe ..."This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")
Aquí está el error:
Te digo qué, sé que las personas que se sienten cómodas con Regex sienten que su uso evita errores, pero a menudo sigo siendo parcial para detectar cadenas de bytes (pero solo después de haber leído Spolsky en las codificaciones ) para estar absolutamente seguro de que estás obteniendo lo que 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 involuntariamente permitimos más (por ejemplo, ¿es
$10
realmente una cadena válida de "valor de captura" en mi nueva expresión de valor, arriba?) Porque no pensamos lo suficiente . 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 queRegex.Escape
no escapó de los patrones de valores capturados como$0
esperaba en los valores de reemplazo) me volvió loco por un tiempo. La programación es difícil (c) 1842fuente
Aquí hay un método de extensión. No estoy seguro de dónde lo encontré.
fuente
Parece que el método más fácil es simplemente usar el método Reemplazar que se incluye con .Net y ha existido desde .Net 1.0:
Para utilizar este método, debe agregar una referencia al ensamblado Microsoft.VisualBasic. Este ensamblaje es una parte estándar del tiempo de ejecución de .Net, no es una descarga adicional ni está marcado como obsoleto.
fuente
C. Dragon 76
como se esperaba.fuente
Inspirado por la respuesta de cfeduke, hice esta función que usa IndexOf para encontrar el valor anterior en la cadena y luego la reemplaza con el nuevo valor. Utilicé esto en un script SSIS que procesaba millones de filas, y el método regex fue mucho más lento que esto.
fuente
Ampliando la respuesta popular de C. Dragon 76 al convertir su código en una extensión que sobrecarga el
Replace
método predeterminado .fuente
Basado en la respuesta de Jeff Reddy, con algunas optimizaciones y validaciones:
fuente
una versión similar a la de C. Dragon, pero si solo necesita un reemplazo:
fuente
Aquí hay otra opción para ejecutar reemplazos de Regex, ya que no mucha gente parece notar que las coincidencias contienen la ubicación dentro de la cadena:
fuente
fuente
El método de expresión regular debería funcionar. Sin embargo, lo que también puede hacer es poner en minúscula la cadena de la base de datos, poner en minúscula el% de variables% que tiene y luego ubicar las posiciones y longitudes en la cadena en minúscula de la base de datos. Recuerde, las posiciones en una cadena no cambian solo porque está en minúscula.
Luego, usando un bucle que va en reversa (es más fácil, si no lo hace, tendrá que llevar un recuento continuo de hacia dónde se mueven los puntos posteriores) elimine de su cadena en caja no inferior de la base de datos las% variables% por su posición y longitud e inserte los valores de reemplazo.
fuente
(Ya que todos están intentando esto). Aquí está mi versión (con comprobaciones nulas, y entrada correcta y escape de reemplazo) ** Inspirado en Internet y otras versiones:
Uso:
fuente
Permíteme presentar mi caso y luego puedes hacerme pedazos si quieres.
Regex no es la respuesta para este problema: demasiado lento y memoria hambrienta, en términos relativos.
StringBuilder es mucho mejor que la secuencia de cadenas.
Dado que este será un método de extensión para complementar
string.Replace
, creo que es importante hacer coincidir cómo funciona, por lo tanto, lanzar excepciones para los mismos problemas de argumento es importante, ya que es devolver la cadena original si no se realizó un reemplazo.Creo que tener un parámetro StringComparison no es una buena idea. Lo intenté pero el caso de prueba mencionado originalmente por michael-liu mostró un problema:
Si bien IndexOf coincidirá, hay una falta de coincidencia entre la longitud de la coincidencia en la cadena de origen (1) y oldValue.Length (2). Esto se manifestó al causar IndexOutOfRange en algunas otras soluciones cuando oldValue.Length se agregó a la posición de coincidencia actual y no pude encontrar una forma de evitar esto. Regex no coincide con el caso de todos modos, así que tomé la solución pragmática de usar solo
StringComparison.OrdinalIgnoreCase
para mi solución.Mi código es similar a otras respuestas, pero mi giro es que busco una coincidencia antes de tomar la molestia de crear un
StringBuilder
. Si no se encuentra ninguno, se evita una asignación potencialmente grande. El código se convierte en un endo{...}while
lugar de unwhile{...}
He realizado algunas pruebas exhaustivas con otras respuestas y esto salió fraccionalmente más rápido y usó un poco menos de memoria.
fuente