Expressions régulières Python non gourmandes


151

Comment créer une expression régulière python comme "(.*)"celle-ci, étant donné les "a (b) c (d) e"correspondances python "b"au lieu de "b) c (d"?

Je sais que je peux utiliser à la "[^)]"place de ".", mais je recherche une solution plus générale qui garde mon regex un peu plus propre. Existe-t-il un moyen de dire à python "hey, correspond à ceci dès que possible"?

Réponses:


209

Tu cherches le tout-puissant *?

Extrait de la documentation, Greedy versus Non-Greedy

les qualificatifs non avides *?, +?, ??ou {m,n}?[...] match peu de texte que possible.


Selon Internet Archive, tout ce lien pointé était une copie de la documentation du module Python "re", donc le lien de Trey fonctionne aussi bien.
spiffytech

2
quel est le nom anglais commun pour cela *??
Trevor Boyd Smith le

Caractères génériques @Trevor Boyd Smith
Serge

3
C'est ce qu'on appelle le qualificatif "non gourmand"
brunetton

65
>>> x = "a (b) c (d) e"
>>> re.search(r"\(.*\)", x).group()
'(b) c (d)'
>>> re.search(r"\(.*?\)", x).group()
'(b)'

Selon la documentation :

Les qualificatifs « *», « +» et « ?» sont tous gourmands; ils correspondent à autant de texte que possible. Parfois, ce comportement n'est pas souhaité; si l'ER <.*>est comparé à « <H1>title</H1>», il correspondra à la chaîne entière, et pas seulement à « <H1>». L'ajout de « ?» après que le qualificatif lui fait effectuer le match de manière non gourmande ou minimale; aussi peu de caractères que possible seront appariés. L'utilisation .*?dans l'expression précédente ne correspondra qu'à « <H1>».


14

Cela ne \\(.*?\\)marcherait pas ? C'est la syntaxe non gourmande.


5

Comme les autres l'ont dit en utilisant le? Le modificateur sur le quantificateur * résoudra votre problème immédiat, mais attention, vous commencez à vous égarer dans des zones où les expressions régulières cessent de fonctionner et vous avez besoin d'un analyseur à la place. Par exemple, la chaîne "(foo (bar)) baz" vous posera des problèmes.


5

Utiliser une correspondance non gaie est un bon début, mais je vous suggère également de reconsidérer toute utilisation de .*- qu'en est-il de cela?

groups = re.search(r"\([^)]*\)", x)

3

Voulez-vous qu'il corresponde à "(b)"? Faites comme Zitrax et Paolo l'ont suggéré. Voulez-vous qu'il corresponde à "b"? Faire

>>> x = "a (b) c (d) e"
>>> re.search(r"\((.*?)\)", x).group(1)
'b'

0

Pour commencer, je ne suggère pas d'utiliser "*" dans les expressions régulières. Oui, je sais, c'est le délimiteur multi-caractères le plus utilisé, mais c'est quand même une mauvaise idée. C'est parce que, bien qu'il corresponde à n'importe quelle quantité de répétition pour ce caractère, "any" inclut 0, ce qui est généralement quelque chose pour lequel vous voulez lancer une erreur de syntaxe, pas accepter. Au lieu de cela, je suggère d'utiliser le +signe, qui correspond à toute répétition de longueur> 1. De plus, d'après ce que je peux voir, vous avez affaire à des expressions entre parenthèses de longueur fixe. En conséquence, vous pouvez probablement utiliser la {x, y}syntaxe pour spécifier spécifiquement la longueur souhaitée.

Cependant, si vous avez vraiment besoin d'une répétition non gourmande, je vous suggère de consulter le tout-puissant ?. Ceci, lorsqu'il est placé après à la fin de tout spécificateur de répétition regex, forcera cette partie de l'expression régulière à trouver le moins de texte possible.

Cela étant dit, je serais très prudent avec le ?car il, comme le tournevis sonique dans Dr. Who, a tendance à faire, comment devrais-je le dire, des choses "légèrement" indésirables si elles ne sont pas soigneusement calibrées. Par exemple, pour utiliser votre exemple d'entrée, il identifierait ((1)(notez l'absence d'un deuxième rparen) comme une correspondance.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.