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)
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)
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
- Recibirá el error "sre_constants.error: grupo no coincidente" de una expresión regular de Python 2.7.
-
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)
ocompiled.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.