regex para que coincida, pero solo reemplace parte del patrón, en python
Todos los ejemplos que he encontrado sobre el desbordamiento de la pila son demasiado complicados para que pueda realizar ingeniería inversa .
Considere este ejemplo de juguete
s = "asdfasd a_b dsfd"
quiero s = "asdfasd a'b dsfd"
Es decir: busque dos caracteres separados por un guión bajo y reemplace ese guión bajo con un apóstrofo
Intento:
re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"
Pensé que ()
se suponía que iban a resolver este problema.
Aún más confuso es el hecho de que parece que encontramos con éxito el carácter que queremos reemplazar:
re.findall("[a-z](_)[a-z]",s)
#['_']
¿Por qué no se reemplaza esto?
Gracias
Respuestas
Utilice patrones de anticipación y retroceso:
re.sub("(?<=[a-z])_(?=[a-z])","'",s)
Los patrones de mirar adelante / atrás tienen un ancho cero y, por lo tanto, no reemplazan nada.
UPD:
- El problema era que
re.sub
reemplazaría toda la expresión coincidente, incluidas la letra anterior y la siguiente. re.findall
todavía coincidía con la expresión completa, pero también tenía un grupo (el paréntesis dentro), que usted observó. Todo el partido estaba quietoa_b
- Las expresiones lookahead / lookbehind comprueban que la búsqueda esté precedida / seguida de un patrón, pero no la incluya en la coincidencia.
- otra opción era crear varios grupos y poner esos grupos en el reemplazo:
re.sub("([a-z])_([a-z])", r"\1'\2", s)
Cuando se usa re.sub
, el texto a conservar debe ser capturado, el texto a eliminar no.
Utilizar
re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)
Ver prueba .
EXPLICACIÓN
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of \1
--------------------------------------------------------------------------------
_ '_'
--------------------------------------------------------------------------------
(?= look ahead to see if there is:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of look-ahead
Código Python :
import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))
Salida:
asdfasd a'b dsfd
El re.sub
sustituirá a todo lo que corresponde.
Existe una forma más general de resolver su problema y no necesita volver a modificar su expresión regular.
Código a continuación:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0)) if _reg else r
#
re.sub(reg,repl, s)
salida: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'
Por supuesto, si su caso no contiene grupos, su código puede tener este aspecto:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0))
#
re.sub(reg,repl, s)