python regex python-2.x

python - Cadena vacía en lugar de error de grupo no coincidente



regex python-2.x (3)

Causa principal

Antes de Python 3.5, las referencias a grupos de captura fallidos en Python re.sub no se re.sub con una cadena vacía. Aquí está la descripción del error 1519638 en bugs.python.org . Por lo tanto, cuando se usa una referencia a un grupo que no participó en el partido, se produjo un error.

Hay dos formas de solucionar ese problema.

Solución 1: Agregar alternativas vacías para hacer obligatorios los grupos opcionales

Puede reemplazar todos los grupos de captura opcionales (aquellas construcciones como (/d+)? ) Por obligatorias con una alternativa vacía (es decir (/d+|) ).

Aquí hay un ejemplo de la falla :

import re old = ''regexregex'' new = re.sub(r''regex(group)?regex'', r''something/1something'', old) print(new)

Reemplazando una línea con

new = re.sub(r''regex(group|)regex'', r''something/1something'', old)

Funciona.

Solución 2: usar la expresión lambda en el reemplazo y verificar si el grupo no es None

Este enfoque es necesario si tiene grupos opcionales dentro de otro grupo opcional.

Puede usar un lambda en la parte de reemplazo para verificar si el grupo está inicializado, no None , con lambda m: m.group(n) or '''' . Use esta solución en su caso , porque tiene dos referencias inversas - # 3 y # 4 - en el patrón de reemplazo, pero algunas coincidencias (ver Coincidencia 1 y 3) no tienen el Grupo de captura 3 inicializado. Ocurre porque toda la primera parte - (/s*/{{2}funcA(ka|)/s*/|/s*([^}]*)/s*/}{2}/s*|) - no participa en la partida, y el grupo de captura interno 3 (es decir, ([^}]*) ) simplemente no se llena incluso después de agregar una alternativa vacía .

re.sub(r''(?i)(/s*/{{2}funcA(ka|)/s*/|/s*([^/}]*)/s*/}{2}/s*|)/{{2}funcB/s*/|/s*([^/}]*)/s*/}{2}/s*'', r"/n | funcA"+str(n)+r" = /3/n | funcB"+str(n)+r" = /4/n | string"+str(n)+r" = /n", text, count=1)

debe reescribirse con

re.sub(r''(?i)(/s*{{funcA(ka|)/s*/|/s*([^}]*)/s*}}/s*|){{funcB/s*/|/s*([^}]*)/s*}}/s*'', lambda m: r"/n | funcA"+str(n)+r" = " + (m.group(3) or '''') + "/n | funcB" + str(n) + r" = " + (m.group(4) or '''') + "/n | string" + str(n) + r" = /n", text, count=1)

Ver demostración de IDEONE

import re text = r'''''' {{funcB|param1}} *some string* {{funcA|param2}} {{funcB|param3}} *some string2* {{funcB|param4}} *some string3* {{funcAka|param5}} {{funcB|param6}} *some string4* '''''' for n in (range(1,(text.count(''funcB'')+1))): text = re.sub(r''(?i)(/s*/{{2}funcA(ka|)/s*/|/s*([^/}]*)/s*/}{2}/s*|)/{{2}funcB/s*/|/s*([^/}]*)/s*/}{2}/s*'', lambda m: r"/n | funcA"+str(n)+r" = "+(m.group(3) or '''')+"/n | funcB"+str(n)+r" = "+(m.group(4) or '''')+"/n | string"+str(n)+r" = /n", text, count=1) assert text == r'''''' | funcA1 = | funcB1 = param1 | string1 = *some string* | funcA2 = param2 | funcB2 = param3 | string2 = *some string2* | funcA3 = | funcB3 = param4 | string3 = *some string3* | funcA4 = param5 | funcB4 = param6 | string4 = *some string4* '''''' print ''ok''

Tengo este pedazo de código:

for n in (range(1,10)): new = re.sub(r''(regex(group)regex)?regex'', r''something''+str(n)+r''/1'', old, count=1)

Lanza el error de grupo sin igual. Pero si no coincide, quiero agregar una cadena vacía allí en lugar de arrojar un error. ¿Cómo podría lograr esto?

Nota: Mi código completo es mucho más complicado que este ejemplo. Pero si encuentra una mejor solución sobre cómo iterar sobre las coincidencias y agregar un número dentro, podría compartir. Mi código completo:

for n in (range(1,(text.count(''soutez'')+1))): text = re.sub(r''(?i)(/s*/{{2}infobox medaile reprezentant(ka)?/s*/|/s*([^/}]*)/s*/}{2}/s*)?/{{2}infobox medaile soutez/s*/|/s*([^/}]*)/s*/}{2}/s*'', r"/n | reprezentace"+str(n)+r" = /3/n | soutez"+str(n)+r" = /4/n | medaile"+str(n)+r" = /n", text, count=1)


Miré esto de nuevo.
Una nota de que es desafortunado que tengas que lidiar con NULL ,
pero aquí están las reglas que debes seguir.

El siguiente coincide con todos con éxito coincide con nada.
Tienes que hacer esto para descubrir las reglas.

No es tan simple como puedes pensar. Mire de cerca los resultados.
No hay una forma aparente y firme de forma para saber si obtendrá NULL o VACÍO.

Sin embargo, mirándolo más de cerca, las reglas salen y son bastante simples.
Estas reglas deben seguirse si le importa NULL.

Solo hay dos reglas:

Regla n. ° 1: cualquier grupo de códigos que no se pueda alcanzar, dará como resultado NULL

(?<Alt_1> # (1 start) (?<a> a )? # (2) (?<b> b? ) # (3) )? # (1 end) | (?<Alt_2> # (4 start) (?<c> c? ) # (5) (?<d> d? ) # (6) ) # (4 end)

** Grp 0 - ( pos 0 , len 0 ) EMPTY ** Grp 1 [Alt_1] - ( pos 0 , len 0 ) EMPTY ** Grp 2 [a] - NULL ** Grp 3 [b] - ( pos 0 , len 0 ) EMPTY ** Grp 4 [Alt_2] - NULL ** Grp 5 [c] - NULL

Regla n. ° 2: cualquier GRUPO de código que no pueda coincidir en el INTERIOR dará como resultado NULL

(?<A_1> # (1 start) (?<a1> a? ) # (2) )? # (1 end) (?<A_2> # (3 start) (?<a2> a )? # (4) )? # (3 end) (?<A_3> # (5 start) (?<a3> a ) # (6) )? # (5 end) (?<A_4> # (7 start) (?<a4> a )? # (8) ) # (7 end)

** Grp 0 - ( pos 0 , len 0 ) EMPTY ** Grp 1 [A_1] - ( pos 0 , len 0 ) EMPTY ** Grp 2 [a1] - ( pos 0 , len 0 ) EMPTY ** Grp 3 [A_2] - ( pos 0 , len 0 ) EMPTY ** Grp 4 [a2] - NULL ** Grp 5 [A_3] - NULL ** Grp 6 [a3] - NULL ** Grp 7 [A_4] - ( pos 0 , len 0 ) EMPTY ** Grp 8 [a4] - NULL


Simplificar:

Problema

  1. Recibirá el error "sre_constants.error: grupo no coincidente" de una expresión regular de Python 2.7.
  2. Tiene cualquier patrón de expresiones regulares con grupos opcionales (con o sin expresiones anidadas) y está tratando de usar esos grupos en su argumento re.sub(pattern, *repl*, string) o compiled.sub(*repl*, string) )

Solución:

Para obtener resultados, devuelva match.group(1) lugar de /1 (o 2, 3, etc.). Eso es; No hay o es necesario. Los resultados del grupo se pueden devolver con una función o una lambda.

Ejemplo

Está utilizando una expresión regular común para eliminar los comentarios de estilo C. Su diseño utiliza un grupo opcional 1 para pasar por pseudo-comentarios que no deben eliminarse (si existen).

pattern = r''//.*|//*[/s/S]*?/*/|("(//.|[^"])*")'' regex = re.compile(pattern)

El uso de /1 falla con el error: "sre_constants.error: grupo no coincidente":

return regex.sub(r''/1'', string)

El uso de .group(1) tiene éxito:

return regex.sub(lambda m: m.group(1), string)

Para aquellos que no están familiarizados con lambda, esta solución es equivalente a:

def optgroup(match): return match.group(1) return regex.sub(optgroup, string)

Vea la respuesta aceptada para una excelente discusión de por qué /1 falla debido al error 1519638. Si bien la respuesta aceptada es autorizada, tiene dos deficiencias: 1) el ejemplo de la pregunta original es tan complicado que dificulta la lectura de la solución del ejemplo, y 2) sugiere devolver un grupo o una cadena vacía; eso no es necesario, simplemente puede llamar a .group() en cada coincidencia.