Búsqueda positiva y negativa en expresiones regulares de Python
A veces necesitas resolver un problema de este tipo:
encontrar la cadena 'aaa' y reemplazarla
por '!', pero solo si después de
'aaa' hay 'x', y esta
'x' no debe ser reemplazada. Si intentamos
resolver el problema 'directamente',
no tendremos éxito:
txt = 'aaax baaa'
res = re.sub('aaax', '!', txt)
print(res) # mostrará '! baaa', pero queríamos '!x baaa'
Búsqueda hacia adelante
Para resolver el problema, necesitamos una forma de decir
que 'x' no debe ser reemplazada. Esto se hace
con paréntesis especiales (?= ),
que solo verifican, pero no consumen caracteres.
Estos paréntesis se llaman búsqueda positiva hacia adelante. Positiva - porque 'x'
(en nuestro caso) debe estar presente - solo entonces
ocurrirá el reemplazo.
Apliquemos estos paréntesis para resolver nuestro problema:
txt = 'aaax baaa'
res = re.sub('aaa(?=x)', '!', txt)
print(res) # mostrará '!x aaab
También existe la búsqueda negativa hacia adelante
- (?! ) - que, por el contrario, indica
que algo no debe estar presente. En el siguiente
ejemplo, el reemplazo ocurrirá solo si
después de 'aaa' NO hay 'x':
txt = 'aaax aaab'
res = re.sub('aaa(?!x)', '!', txt)
print(res) # mostrará 'aaax !b'
Búsqueda hacia atrás
De manera similar, existe la búsqueda positiva
hacia atrás - (?<= ). En el
siguiente ejemplo, el reemplazo ocurrirá solo
si antes de 'aaa' hay 'x':
txt = 'xaaa'
res = re.sub('(?<=x)aaa', '!', txt)
print(res) # mostrará 'x!'
Y también existe la búsqueda negativa hacia atrás
- (?<! ). En el siguiente ejemplo
el reemplazo ocurrirá solo si antes de
'aaa' NO hay 'x':
txt = 'baaa'
res = re.sub('(?<!x)aaa', '!', txt)
print(res) # mostrará 'b!'
Problemas prácticos
Dada una cadena que contiene nombres de funciones:
txt = 'func1() func2() func3()'
Obtenga un array con los nombres de las funciones de la cadena.
Dada una cadena con una etiqueta:
txt = '<a href="" class="eee" id="zzz">'
Obtenga un array con los nombres de los atributos de esta etiqueta.
Dada una cadena con variables:
txt = '$aaa $bbb $ccc xxxx'
Obtenga las subcadenas que están precedidas por el símbolo de dólar.