Tengo la siguiente cadena, donde trato de hacer coincidir una cadena del 'foo' correspondiente con 'bar = 1', 'bar = 2' o 'bar = 3'. Así que solo un partido a la vez.

file_header

foo lorem ipsum \pope
24 dolor sit amet, consectetur adipisici elit
Excepteur sint obcaecat cupiditat non 
gnu blu bar=1

foo lorem ipsum \
@>@!@ consectetur adipisici elit
gnu blu bar=2
foo lorem ipsum
23 dolor sit amet, consectetur adipisici elit
gnu blu bar=3

foo ... etc

Intenté todo, desde un simple ^foo.*?bar=2$ hasta algo como ^(?!\bfoo\b.*\bfoo\b).*\bfoo\b.*bar=2$. Pero con multilínea y dotall activados, siempre coincidirá con el primer 'foo' o incluso marcará el encabezado del archivo completo. :(

Parece que un comportamiento no codicioso no es posible, mientras se usa multilínea y dotall.

1
CptSausage 10 may. 2016 a las 18:19

3 respuestas

La mejor respuesta

Puedes usar una ficha codiciosa templada como

^foo(?:(?!^foo|bar=2$).)*bar=2$

(?:(?!^foo|bar=2$).)* coincide con cualquier texto que no sea foo (al comienzo de una línea / cadena) y no bar=2 al final de la línea / cadena.

Consulte la demostración de expresiones regulares. Sin embargo, tal construcción consume muchos recursos, se recomienda desenrollarla. Aquí hay una opción:

^foo[^\nb]*(?:\n(?!foo)[^\nb]*|b(?!ar$)[^\nb]*)*bar=2$

Consulte otra demostración.

1
Wiktor Stribiżew 10 may. 2016 a las 15:26

La codicia funciona de izquierda a derecha

No tiene nada que ver con MULTILINE o DOTALL, es ese operador no codicioso solo afecta el final del partido, no el inicio.

Para cumplir su deseo, agregue .* delante de su patrón.

>>> re.findall(r'.*(foo.*?bar=1)', s, re.DOTALL)
['foo lorem ipsum \\pope\n24 dolor sit amet, consectetur adipisici elit\nExcepteur sint obcaecat cupiditat non \ngnu blu bar=1']
>>> re.findall(r'.*(foo.*?bar=2)', s, re.DOTALL)
['foo lorem ipsum @>@!@ consectetur adipisici elit\ngnu blu bar=2']
>>> re.findall(r'.*(foo.*?bar=3)', s, re.DOTALL)
['foo lorem ipsum\n23 dolor sit amet, consectetur adipisici elit\ngnu blu bar=3']
1
pacholik 11 may. 2016 a las 09:51

Este programa encuentra todas las ocurrencias no superpuestas de foo <stuff> bar=<number>. Tenga en cuenta el uso exitoso del operador no codicioso en re.MULTILINE - modo usando esta expresión: ^foo.*?bar=\d+$

import re
from pprint import pprint

data = '''
file_header

foo lorem ipsum \pope
24 dolor sit amet, consectetur adipisici elit
Excepteur sint obcaecat cupiditat non 
gnu blu bar=1

foo lorem ipsum \
@>@!@ consectetur adipisici elit
gnu blu bar=2
foo lorem ipsum
23 dolor sit amet, consectetur adipisici elit
gnu blu bar=3
'''

matches = re.findall(r'^foo.*?bar=\d+$', data, re.DOTALL|re.MULTILINE)
pprint (matches)

Resultado:

['foo lorem ipsum \\pope\n24 dolor sit amet, consectetur adipisici elit\nExcepteur sint obcaecat cupiditat non \ngnu blu bar=1',
 'foo lorem ipsum @>@!@ consectetur adipisici elit\ngnu blu bar=2',
 'foo lorem ipsum\n23 dolor sit amet, consectetur adipisici elit\ngnu blu bar=3']
1
Robᵩ 10 may. 2016 a las 15:31