validar solo regulares regular numeros expresiones expresion especiales espacio ejemplos cualquier caracteres caracter blanco alfanumerico c# python regex language-agnostic

c# - solo - expresiones regulares ejemplos



¿Se puede usar Regex para esta manipulación de cadenas en particular? (9)

Necesito reemplazar el carácter (decir) x con el carácter (por ejemplo) P en una cadena, pero solo si está contenido en una subcadena entre comillas. Un ejemplo lo aclara:

axbx''cxdxe''fxgh''ixj''k -> axbx''cPdPe''fxgh''iPj''k

Supongamos, en aras de la simplicidad, que las citas siempre vienen en pares.

La forma obvia es simplemente procesar la cadena un carácter a la vez (un enfoque de máquina de estado simple);
sin embargo, me pregunto si se pueden usar expresiones regulares para hacer todo el procesamiento de una vez.

Mi idioma de destino es C #, pero supongo que mi pregunta se refiere a cualquier idioma que tenga compatibilidad incorporada o de biblioteca para expresiones regulares.


Convertí el código python de Greg Hewgill a C # ¡y funcionó!

[Test] public void ReplaceTextInQuotes() { Assert.AreEqual("axbx''cPdPe''fxgh''iPj''k", Regex.Replace("axbx''cxdxe''fxgh''ixj''k", @"x(?=[^'']*''([^'']|''[^'']*'')*$)", "P")); }

Esa prueba pasó.


El truco es usar un grupo que no sea de captura para que coincida con la parte de la cadena que sigue a la coincidencia (carácter x ) que estamos buscando. Intentar hacer coincidir la cuerda hasta x solo encontrará la primera o la última ocurrencia, dependiendo de si se usan cuantificadores no codiciosos. Aquí está la idea de Greg transpuesta a Tcl, con comentarios.

set strIn {axbx''cxdxe''fxgh''ixj''k} set regex {(?x) # enable expanded syntax # - allows comments, ignores whitespace x # the actual match (?= # non-matching group [^'']*'' # match to end of current quoted substring ## ## assuming quotes are in pairs, ## make sure we actually were ## inside a quoted substring ## by making sure the rest of the string ## is what we expect it to be ## ( [^'']* # match any non-quoted substring | # ...or... ''[^'']*'' # any quoted substring, including the quotes )* # any number of times $ # until we run out of string :) ) # end of non-matching group } #the same regular expression without the comments set regexCondensed {(?x)x(?=[^'']*''([^'']|''[^'']*'')*$)} set replRegex {P} set nMatches [regsub -all -- $regex $strIn $replRegex strOut] puts "$nMatches replacements. " if {$nMatches > 0} { puts "Original: |$strIn|" puts "Result: |$strOut|" } exit

Esto imprime:

3 replacements. Original: |axbx''cxdxe''fxgh''ixj''k| Result: |axbx''cPdPe''fxgh''iPj''k|


Lamento romper tus esperanzas, pero necesitas un autómata pushdown para hacer eso. Hay más información aquí: Pushdown Autómata

En resumen, las expresiones regulares, que son máquinas de estado finito solo pueden leer y no tienen memoria, mientras que el autómata pushdown tiene una pila y capacidades de manipulación.

Editar: ortografía ...


No con expresiones regulares regulares Las expresiones regulares no tienen "memoria", por lo que no pueden distinguir entre citas "internas" o "externas".

Necesitas algo más poderoso, por ejemplo, usando gema sería directo:

''<repl>''=$0 repl:x=P


Pude hacer esto con Python:

>>> import re >>> re.sub(r"x(?=[^'']*''([^'']|''[^'']*'')*$)", "P", "axbx''cxdxe''fxgh''ixj''k") "axbx''cPdPe''fxgh''iPj''k"

Lo que hace es usar la coincidencia que no captura (? = ...) para verificar que el carácter x se encuentre dentro de una cadena entrecomillada. Busca algunos caracteres que no sean las comillas hasta la siguiente cita, luego busca una secuencia de caracteres individuales o grupos de caracteres citados, hasta el final de la cadena.

Esto se basa en su suposición de que las comillas siempre están equilibradas. Esto tampoco es muy eficiente.


#!/usr/bin/perl -w use strict; # Break up the string. # The spliting uses quotes # as the delimiter. # Put every broken substring # into the @fields array. my @fields; while (<>) { @fields = split /''/, $_; } # For every substring indexed with an odd # number, search for x and replace it # with P. my $count; my $end = $#fields; for ($count=0; $count < $end; $count++) { if ($count % 2 == 1) { $fields[$count] =~ s/a/P/g; } }

¿No haría este pedazo el trabajo?


Una solución más general (y más simple) que permite cotizaciones sin pares.

  1. Buscar cadena citada
  2. Reemplazar ''x'' por ''P'' en la cadena

    #!/usr/bin/env python import re text = "axbx''cxdxe''fxgh''ixj''k" s = re.sub("''.*?''", lambda m: re.sub("x", "P", m.group(0)), text) print s == "axbx''cPdPe''fxgh''iPj''k", s # -> True axbx''cPdPe''fxgh''iPj''k


Pattern: (?s)/G((?:^[^'']*''|(?<=.))(?:''[^'']*''|[^''x]+)*+)x Replacement: /1P

  1. /G - Ancla cada partida al final de la anterior, o el inicio de la cadena.
  2. (?:^[^'']*''|(?<=.)) - Si está al principio de la cadena, haga coincidir la primera cita.
  3. (?:''[^'']*''|[^''x]+)*+ - Relaciona cualquier bloque de caracteres sin comillas, o cualquier caracter (sin cita) hasta una ''x''.

Un barrido a través de la cadena fuente, a excepción de un solo personaje detrás de la mirada.


Discusiones similares sobre el texto equilibrado reemplazan: ¿Se pueden usar expresiones regulares para unir patrones anidados?

Aunque puedes probar esto en Vim, pero funciona bien solo si la cadena está en una línea, y solo hay un par de ''s.

:%s:/(''[^'']*/)x/([^'']*''/):/1P/2:gci

Si hay un par más o incluso un desequilibrado, podría fallar. Así es como incluí la bandera c confirmar en el comando ex .

Lo mismo se puede hacer con sed, sin la interacción, o con awk para que pueda agregar alguna interacción.

Una posible solución es romper las líneas en pares de '' s luego puedes hacerlo con la solución vim.