Quantificateurs avides vs réticents vs possessifs

357

J'ai trouvé cet excellent tutoriel sur les expressions régulières et bien que je comprenne intuitivement ce que font les quantificateurs "avides", "réticents" et "possessifs", il semble y avoir un sérieux trou dans ma compréhension.

Plus précisément, dans l'exemple suivant:

Enter your regex: .*foo  // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.

Enter your regex: .*?foo  // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.

Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.

L'explication mentionne avoir mangé la chaîne d'entrée entière, des lettres ont été consommées , le matcher a reculé , l'occurrence la plus à droite de "foo" a été régurgitée , etc.

Malheureusement, malgré les belles métaphores, je ne comprends toujours pas ce qui est mangé par qui ... Connaissez-vous un autre tutoriel qui explique (de manière concise) comment fonctionnent les moteurs d'expressions régulières?

Alternativement, si quelqu'un peut expliquer dans une formulation quelque peu différente le paragraphe suivant, ce serait très apprécié:

Le premier exemple utilise le quantificateur gourmand. * Pour trouver "n'importe quoi", zéro ou plusieurs fois, suivi des lettres "f" "o" "o". Parce que le quantificateur est gourmand, la partie. * De l'expression mange d'abord la chaîne d'entrée entière. À ce stade, l'expression globale ne peut pas réussir, car les trois dernières lettres ("f" "o" "o") ont déjà été consommées ( par qui? ). Ainsi, le matcher recule lentement ( de droite à gauche? ) Une lettre à la fois jusqu'à ce que l'occurrence la plus à droite de "foo" soit régurgitée ( qu'est-ce que cela signifie? ), À quel point la correspondance réussit et la recherche se termine.

Le deuxième exemple, cependant, est réticent, il commence donc par consommer d'abord ( par qui? ) "Rien". Parce que "foo" n'apparaît pas au début de la chaîne, il est obligé d'avaler ( qui avale?) La première lettre (un "x"), ce qui déclenche la première correspondance à 0 et 4. Notre harnais de test continue le processus jusqu'à ce que la chaîne d'entrée soit épuisée. Il trouve un autre match à 4 et 13.

Le troisième exemple ne parvient pas à trouver une correspondance car le quantificateur est possessif. Dans ce cas, la chaîne d'entrée entière est consommée par. * +, ( Comment? ) Ne laissant rien pour satisfaire le "foo" à la fin de l'expression. Utilisez un quantificateur possessif pour les situations où vous voulez saisir tout quelque chose sans jamais reculer ( qu'est-ce que signifie reculer? ); il surpassera le quantificateur gourmand équivalent dans les cas où la correspondance n'est pas immédiatement trouvée.

Regex Rookie
la source
22
Maximal quantificateurs aiment *, +et ?sont avides. Minimal quantificateurs aiment *?, +?et ??sont paresseux. Possessifs quantificateurs aiment *+, ++et ?+sont collants.
tchrist
6
Cette question a été ajoutée à la FAQ sur l'expression régulière de débordement de pile , sous "Quantificateurs> Plus sur les différences ...".
aliteralmind
Intérêt: Les tutoriels Java ™ - Différences entre les quantificateurs gourmands, réticents et possessifs - Faites défiler vers le bas pour voir la section.
Guy Coder

Réponses:

495

Je vais essayer.

Un quantificateur gourmand correspond d'abord autant que possible. Ainsi, le .*correspond à la chaîne entière. Ensuite, le matcher essaie de faire correspondre les éléments fsuivants, mais il ne reste aucun caractère. Ainsi, il "revient en arrière", ce qui fait que le quantificateur gourmand correspond à un caractère de moins (en laissant le "o" à la fin de la chaîne sans correspondance). Cela ne correspond toujours pas fà l'expression rationnelle, donc il revient en arrière d'une étape supplémentaire, ce qui fait que le quantificateur gourmand correspond à nouveau à un caractère de moins (en laissant le "oo" à la fin de la chaîne sans correspondance). Cela ne correspond toujours pas au fdans l'expression régulière, donc il revient en arrière d'une étape de plus (en laissant le "foo" à la fin de la chaîne sans correspondance). Maintenant, le match correspond enfin fà l'expression rationnelle,oosont assortis aussi. Succès!

Un quantificateur réticent ou "non gourmand" correspond d'abord le moins possible. Donc, le .*ne correspond à rien au début, laissant la chaîne entière inégalée. Ensuite, le matcher essaie de faire correspondre les éléments fsuivants, mais la partie sans correspondance de la chaîne commence par "x", ce qui ne fonctionne pas. Ainsi, le matcher revient en arrière, ce qui fait que le quantificateur non gourmand correspond à un caractère de plus (maintenant il correspond au "x", laissant "fooxxxxxxfoo" inégalé). Ensuite, il essaie de faire correspondre le f, qui réussit, et le oet le suivant odans la correspondance d'expression régulière aussi. Succès!

Dans votre exemple, il recommence alors le processus avec la partie non correspondante restante de la chaîne, "xxxxxxfoo", en suivant le même processus.

Un quantificateur possessif est comme le quantificateur gourmand, mais il ne revient pas en arrière. Il commence donc par faire .*correspondre la chaîne entière, ne laissant rien d'inégalé. Ensuite, il ne reste plus rien à faire avec le fdans l'expression régulière. Puisque le quantificateur possessif ne revient pas en arrière, la correspondance échoue là-bas.

Anomie
la source
15
+1 Bonne réponse. J'ajouterais seulement: Allez lire Mastering Regular Expressions (3rd Edition)
ridgerunner
@Anomie un peu en retard mais, dans la partie possessive, je pense que vous vouliez dire Donc ça commence par .*+ (remarquez le "+")
RD
3
que fait alors exactement le quantificateur possessif? si cela ne correspond pas à cela? (Je veux dire à quoi ça sert, si vous ne pouvez pas avoir de personnages après)
relipse
4
@relipse: Vous l'utiliseriez dans une situation où vous savez que le retour arrière n'aidera pas, probablement pas avec .*+tout ce qui correspond. Par exemple, si vous avez un modèle [xyz]*foo, il est impossible que le retour en arrière des x, y et z correspondant au [xyz]*bit permette au foobit suivant de correspondre, vous pouvez donc accélérer les choses en le rendant possessif.
Anomie
4
@moodboom, il n'y a jamais de cas (fait mathématique) où des quantificateurs possessifs produiront une correspondance qui ne sera pas produite par de simples quantificateurs gourmands. Il y a des cas occasionnels où ils produiront une non-correspondance lorsque des quantificateurs gourmands produiraient une correspondance. Pour TOUS les autres cas (où gourmand et possessif produisent les mêmes résultats), les quantificateurs possessifs donnent un gain de performance.
Wildcard
49

C'est juste ma sortie d'entraînement pour visualiser la scène-

Image visuelle

SIslam
la source
3
Sauf que je pense que le dernier cas, possessif, ne devrait pas avoir n passes - il suffit de saisir la chaîne entière à la fois.
traitez bien vos mods le
@phyzome Je pense que ça va maintenant?
SIslam
1
Merci pour l'explication visuelle :)
Lars Moelleken
En EXPRESSION .*?foo(), les [f] [o] [o]rectangles ne doivent-ils pas être jaunes dans le 5th pass?
tonix
1
@tonix oui! La coloration jaune doit être effectuée pour la partie correspondante dans l'expression .*?fooet .*+foo.
SIslam
24

Je n'ai jamais entendu les termes exacts «régurgiter» ou «reculer» auparavant; l'expression qui remplacerait ces derniers est "retour en arrière", mais "régurgiter" semble être une expression aussi bonne que n'importe laquelle pour "le contenu qui avait été provisoirement accepté avant que le retour en arrière ne le rejette".

La chose importante à réaliser sur la plupart des moteurs d'expression régulière est qu'ils font marche arrière : ils accepteront provisoirement une correspondance partielle potentielle, tout en essayant de faire correspondre le contenu entier de l'expression régulière. Si l'expression régulière ne peut pas être complètement adapté à la première tentative, le moteur de regex revenir en arrière sur l' un de ses matchs. Il essayera matching *, +, ?, alternance ou {n,m}répétition différemment, et essayez à nouveau. (Et oui, ce processus peut prendre beaucoup de temps.)

Le premier exemple utilise le quantificateur gourmand. * Pour trouver "n'importe quoi", zéro ou plusieurs fois, suivi des lettres "f" "o" "o". Parce que le quantificateur est gourmand, la partie. * De l'expression mange d'abord la chaîne d'entrée entière. À ce stade, l'expression globale ne peut pas réussir, car les trois dernières lettres ("f" "o" "o") ont déjà été consommées ( par qui? ).

Les trois dernières lettres, f, oet oont déjà été consommés par la première .*partie de la règle. Cependant, l'élément suivant dans l'expression régulière f, n'a plus rien dans la chaîne d'entrée. Le moteur sera obligé de revenir en arrière sur sa .*correspondance initiale et d'essayer de faire correspondre tout le dernier caractère. (Il pourrait être intelligent et revenir à tous les trois, sauf les trois derniers, car il contient trois termes littéraux, mais je ne connais pas les détails de mise en œuvre à ce niveau.)

Ainsi, le matcher recule lentement ( de droite à gauche? ) Une lettre à la fois jusqu'à ce que l'occurrence la plus à droite de "foo" ait été régurgitée ( qu'est-ce que cela signifie? ), À laquelle

Cela signifie qu'ils fooavaient provisoirement été inclus lors de l'appariement .*. Parce que cette tentative a échoué, le moteur d'expression régulière essaie d'accepter un caractère de moins dans .*. S'il y avait eu une correspondance réussie avant le .*dans cet exemple, le moteur essaierait probablement de raccourcir la .*correspondance (de droite à gauche, comme vous l'avez souligné, car il s'agit d'un qualificatif gourmand), et s'il ne pouvait pas correspondre toutes les entrées, alors il pourrait être forcé de réévaluer ce qu'il avait correspondu avant le .*dans mon exemple hypothétique.

pointez la correspondance réussit et la recherche se termine.

Le deuxième exemple, cependant, est réticent, il commence donc par consommer d'abord ( par qui? ) "Rien". Parce que "foo"

Le rien initial est consommé par .?*, ce qui consommera la quantité la plus courte possible de tout ce qui permet au reste de l'expression régulière de correspondre.

n'apparaît pas au début de la chaîne, il est obligé d'avaler ( qui avale?) le

Encore une fois, le .?*consomme le premier caractère, après avoir fait marche arrière sur l'échec initial à faire correspondre l'intégralité de l'expression rationnelle avec la correspondance la plus courte possible. (Dans ce cas, le moteur d'expression régulière étend la correspondance .*?de gauche à droite, car il .*?est réticent.)

première lettre (un "x"), qui déclenche la première correspondance à 0 et 4. Notre faisceau de test continue le processus jusqu'à ce que la chaîne d'entrée soit épuisée. Il trouve un autre match à 4 et 13.

Le troisième exemple ne parvient pas à trouver une correspondance car le quantificateur est possessif. Dans ce cas, la chaîne d'entrée entière est consommée par. * +, ( Comment? )

A .*+consommera autant que possible et ne reviendra pas en arrière pour trouver de nouvelles correspondances lorsque l'expression régulière dans son ensemble ne parvient pas à trouver une correspondance. Parce que la forme possessive ne fonctionne pas retours en arrière, vous ne verrez probablement pas beaucoup d' utilisations avec .*+, mais avec des classes de caractères ou des restrictions similaires: account: [[:digit:]]*+ phone: [[:digit:]]*+.

Cela peut accélérer considérablement la correspondance des expressions rationnelles, car vous dites au moteur d'expression régulière qu'il ne devrait jamais revenir en arrière sur les correspondances potentielles si une entrée ne correspond pas. (Si vous deviez écrire tout le code correspondant à la main, cela reviendrait à ne jamais utiliser putc(3)pour «repousser» un caractère d'entrée. Ce serait très similaire au code naïf que l'on pourrait écrire lors d'un premier essai. Sauf que les moteurs d'expression régulière sont bien mieux qu'un seul caractère de push-back, ils peuvent revenir en arrière à zéro et réessayer. :)

Mais plus que les accélérations potentielles, cela peut également vous permettre d'écrire des expressions rationnelles qui correspondent exactement à ce dont vous avez besoin. J'ai du mal à trouver un exemple simple :) mais écrire une expression rationnelle en utilisant des quantificateurs possessifs vs gourmands peut vous donner des correspondances différentes, et l'un ou l'autre peut être plus approprié.

ne laissant rien pour satisfaire le "foo" à la fin de l'expression. Utilisez un quantificateur possessif pour les situations où vous voulez saisir tout quelque chose sans jamais reculer ( qu'est-ce que signifie reculer? ); il surclassera

Dans ce contexte, «reculer» signifie «revenir en arrière» - jeter une tentative de correspondance partielle pour essayer une autre correspondance partielle, qui peut ou non réussir.

le quantificateur gourmand équivalent dans les cas où la correspondance n'est pas immédiatement trouvée.

sarnold
la source
2
Je soupçonne qu'il n'y a jamais de cas où un quantificateur possessif correspondra à quelque chose qu'un quantificateur gourmand ne fera pas. Je crois que ce qui suit le prouve: un quantificateur gourmand correspond toujours autant que possible, puis revient en arrière s'il ne trouve pas de correspondance. Un quantificateur possessif correspond autant que possible, puis se ferme s'il ne trouve pas de correspondance. Donc, il peut y avoir quelque chose qu'un quantificateur gourmand correspond à un quantificateur possessif ne le fera pas, mais pas l'inverse, car ils recherchent tous les deux «l'arbre» ​​dans la même séquence, le quantificateur possessif abandonne simplement plus facilement. ;)
Wildcard
2
Confirmé: "C'est à cela que servent le regroupement atomique et les quantificateurs possessifs: l'efficacité en interdisant le retour en arrière." from regular-expressions.info Ainsi, la déclaration dans cette réponse "Mais plus que des accélérations potentielles, cela peut également vous permettre d'écrire des expressions rationnelles qui correspondent exactement à ce dont vous avez besoin." n'est en fait pas tout à fait exact.
Wildcard
1
@Wildcard, merci pour les commentaires; cela peut expliquer pourquoi j'ai eu du mal à trouver un exemple. Hehe.
sarnold
19

http://swtch.com/~rsc/regexp/regexp1.html

Je ne suis pas sûr que ce soit la meilleure explication sur Internet, mais elle est raisonnablement bien écrite et suffisamment détaillée, et je continue d'y revenir. Vous voudrez peut-être le vérifier.

Si vous voulez un niveau plus élevé (explication moins détaillée), pour les expressions régulières simples comme celle que vous regardez, un moteur d'expression régulière fonctionne par retour arrière. Essentiellement, il choisit ("mange") une section de la chaîne et essaie de faire correspondre l'expression régulière à cette section. Si cela correspond, tant mieux. Sinon, le moteur modifie son choix de la section de la chaîne et essaie de faire correspondre l'expression rationnelle avec cette section, et ainsi de suite, jusqu'à ce qu'il ait essayé tous les choix possibles.

Ce processus est utilisé récursivement: dans sa tentative de faire correspondre une chaîne avec une expression régulière donnée, le moteur divisera l'expression régulière en morceaux et appliquera l'algorithme à chaque morceau individuellement.

La différence entre les quantificateurs gourmands, réticents et possessifs entre lorsque le moteur fait son choix de la partie de la chaîne à essayer de comparer, et comment modifier ce choix s'il ne fonctionne pas la première fois. Les règles sont les suivantes:

  • Un quantificateur gourmand indique au moteur de démarrer avec la chaîne entière (ou au moins, tout ce qui n'a pas déjà été mis en correspondance par les parties précédentes de l'expression régulière) et de vérifier s'il correspond à l'expression rationnelle. Si oui, tant mieux; le moteur peut continuer avec le reste de l'expression rationnelle. Sinon, il essaie à nouveau, mais en supprimant un caractère (le dernier) de la section de la chaîne à vérifier. Si cela ne fonctionne pas, il supprime un autre caractère, etc. Un quantificateur gourmand vérifie donc les correspondances possibles dans l'ordre, du plus long au plus court.

  • Un quantificateur réticent indique au moteur de démarrer avec le morceau de chaîne le plus court possible. S'il correspond, le moteur peut continuer; sinon, il ajoute un caractère à la section de la chaîne vérifiée et essaie cela, et ainsi de suite jusqu'à ce qu'il trouve une correspondance ou que la chaîne entière ait été utilisée. Ainsi, un quantificateur réticent vérifie les correspondances possibles dans l'ordre, du plus court au plus long.

  • Un quantificateur possessif est comme un quantificateur gourmand à la première tentative: il dit au moteur de démarrer en vérifiant la chaîne entière. La différence est que si cela ne fonctionne pas, le quantificateur possessif signale que la correspondance a échoué tout de suite. Le moteur ne modifie pas la section de la chaîne examinée et ne fait plus de tentatives.

C'est pourquoi la correspondance du quantificateur possessif échoue dans votre exemple: le .*+est vérifié par rapport à la chaîne entière, ce qu'il correspond, mais le moteur continue ensuite à rechercher des caractères supplémentaires foo- mais bien sûr, il ne les trouve pas, car vous êtes déjà à la fin de la chaîne. S'il s'agissait d'un quantificateur gourmand, il reviendrait en arrière et essaierait de faire la .*seule correspondance jusqu'à l'avant-dernier caractère, puis jusqu'au troisième au dernier caractère, puis jusqu'au quatrième au dernier caractère, qui réussit parce que seulement alors il y a une foogauche après .*avoir "mangé" la première partie de la chaîne.

David Z
la source
1
Voilà une excellente source. J'adore les diagrammes de machines d'état. :)
Regex Rookie
@Regex Rookie: content que vous l'aimiez :) Cependant, après avoir parcouru ce site, je pense que je devrais préciser que son objectif est de promouvoir une implémentation alternative d'un moteur d'expression régulière. L'algorithme de retour arrière I (partiellement) et d'autres réponses décrivent la manière lente ; il s'agit d'un algorithme complètement distinct de l'idée NFA / DFA décrite dans la page Web. Le retour arrière est simplement plus facile à comprendre, c'est pourquoi c'est ainsi que les expressions régulières sont généralement expliquées aux débutants.
David Z
@David Zaslavsky: Bonne explication. Vos commentaires entre parenthèses dans "Un quantificateur gourmand dit au moteur de démarrer avec la chaîne entière (ou du moins, tout ce qui n'a pas déjà été mis en correspondance par les parties précédentes de l'expression régulière)" sont importants. Ils s'appliquent également aux quantificateurs réticents et possessifs. Cela rend votre explication compatible avec ce qui se passe lorsque nous modifions nos modèles d'exemple de (". * Foo"; ". *? Foo"; et ". * + Foo") en ("foo. *"; "Foo. *? "; et" foo. * + ").
John Bentley
En fait, xfooxxxxxxfoo correspond à. * Foo dans une expression régulière (sens informatique). Le NFA serait un état où il boucle entre lui avec n'importe quel personnage et ensuite il peut passer à la mode. Le DFA serait une simple traduction de ce NFA. Cela peut être fait dans 8 états.
user4951
@ JimThio oui, parce que ce n'est pas un quantificateur possessif.
David Z
13

Voici mon point de vue en utilisant les positions de cellule et d'index (voir le diagramme ici pour distinguer une cellule d'un index).

Gourmand - Correspondre autant que possible au quantificateur gourmand et à toute l'expression régulière. S'il n'y a pas de correspondance, revenez sur le quantificateur gourmand.

Chaîne d'entrée: xfooxxxxxxfoo
Regex :. * Foo

Le Regex ci-dessus comprend deux parties:
(i) '. *' Et
(ii) 'foo'

Chacune des étapes ci-dessous analysera les deux parties. Les commentaires supplémentaires pour une correspondance avec «réussite» ou «échec» sont expliqués entre accolades.

Étape 1:
(i). * = Xfooxxxxxxfoo - PASS ('. *' Est un quantificateur gourmand et utilisera l'intégralité de la chaîne d'entrée)
(ii) foo = Aucun caractère ne reste après l'index 13 - ÉCHEC La
correspondance a échoué.

Étape 2:
(i). * = Xfooxxxxxxfo - PASS (Retour sur le quantificateur gourmand '. *')
(Ii) foo = o - FAIL
Match a échoué.

Étape 3:
(i). * = Xfooxxxxxxf - PASS (Retour sur le quantificateur gourmand '. *')
(Ii) foo = oo - FAIL
Match a échoué.

Étape 4:
(i). * = Xfooxxxxxx - PASS (Retour sur le quantificateur gourmand '. *')
(Ii) foo = foo - PASS
Report MATCH

Résultat: 1 correspondance (s)
J'ai trouvé le texte "xfooxxxxxxfoo" commençant à l'index 0 et se terminant à l'index 13.

Réticent - Correspond le moins possible au quantificateur réticent et correspond à l'ensemble de l'expression rationnelle. s'il n'y a pas de correspondance, ajoutez des caractères au quantificateur réticent.

Chaîne d'entrée: xfooxxxxxxfoo
Regex :. *? Foo

L'expression rationnelle ci-dessus comprend deux parties:
(i) '. *?' et
(ii) «foo»

Étape 1:.
*? = '' (vide) - PASS (Correspondre aussi peu que possible au quantificateur réticent '. *?'. L'index 0 ayant '' est une correspondance.)
foo = xfo - FAIL (Cellule 0,1,2 - ie index entre 0 et 3) Le
match a échoué.

Étape 2:.
*? = x - PASS (Ajouter des caractères au quantificateur réticent '. *?'. La cellule 0 ayant 'x' est une correspondance.)
foo = foo - PASS
Report MATCH

Étape 3:.
*? = '' (vide) - PASS (Correspondre le moins possible au quantificateur réticent '. *?'. L'index 4 ayant '' est une correspondance.)
foo = xxx - FAIL (Cellule 4,5,6 - ie index entre 4 et 7) Le
match a échoué.

Étape 4:.
*? = x - PASS (Ajouter des caractères au quantificateur réticent '. *?'. Cellule 4.)
foo = xxx - FAIL (Cell 5,6,7 - ie index entre 5 et 8) La
correspondance a échoué.

Étape 5:.
*? = xx - PASS (Ajouter des caractères au quantificateur réticent '. *?'. Cellule 4 à 5.)
foo = xxx - FAIL (Cell 6,7,8 - ie index entre 6 et 9) La
correspondance a échoué.

Étape 6:.
*? = xxx - PASS (Ajouter des caractères au quantificateur réticent '. *?'. Cellule 4 à 6.)
foo = xxx - FAIL (Cellule 7,8,9 - c'est-à-dire index entre 7 et 10) La
correspondance a échoué.

Étape 7:.
*? = xxxx - PASS (Ajouter des caractères au quantificateur réticent '. *?'. Cellule 4 à 7.)
foo = xxf - FAIL (Cell 8,9,10 - c'est-à-dire index entre 8 et 11) La
correspondance a échoué.

Étape 8:.
*? = xxxxx - PASS (Ajouter des caractères au quantificateur réticent '. *?'. Cellule 4 à 8.)
foo = xfo - FAIL (Cell 9,10,11 - c'est-à-dire index entre 9 et 12) La
correspondance a échoué.

Étape 9:.
*? = xxxxxx - PASS (Ajouter des caractères au quantificateur réticent '. *?'. Cellule 4 à 9.)
foo = foo - PASS (Cellule 10,11,12 - c'est-à-dire index entre 10 et 13)
Rapport MATCH

Étape 10:.
*? = '' (vide) - PASS (correspond le moins possible au quantificateur réticent '. *?'. L'index 13 est vide.)
foo = Aucun caractère ne reste à faire correspondre - FAIL (il n'y a rien après l'index 13 à faire correspondre)
Match échoué.

Résultat: 2 correspondance (s)
J'ai trouvé le texte "xfoo" commençant à l'index 0 et se terminant à l'index 4.
J'ai trouvé le texte "xxxxxxfoo" commençant à l'index 4 et se terminant à l'index 13.

Possessive - Faites correspondre autant que possible le quantifère possessif et faites correspondre le regex entier. Ne reculez PAS.

Chaîne d'entrée: xfooxxxxxxfoo
Regex :. * + Foo

L'expression rationnelle ci-dessus comprend deux parties: '. * +' Et 'foo'.

Étape 1
:. * + = Xfooxxxxxxfoo - PASS (correspondre autant que possible au quantificateur possessif '. *')
Foo = aucun caractère ne reste à faire correspondre - FAIL (rien à faire correspondre après l'index 13) La
correspondance a échoué.

Remarque: le retour en arrière n'est pas autorisé.

Résultat: 0 match (s)

raka
la source
1

Gourmand: "correspondre à la séquence de caractères la plus longue possible"

Réticent: "correspondre à la séquence de caractères la plus courte possible"

Possessif: C'est un peu étrange car il n'essaye PAS (contrairement aux gourmands et réticents) de trouver une correspondance pour toute l'expression régulière.

Soit dit en passant: aucune implémentation de matcher de motifs regex n'utilisera jamais de retour arrière. Tous les matcher de motifs réels sont extrêmement rapides - presque indépendants de la complexité de l'expression régulière!

Tilo Koerbs
la source
Pour autant que je sache, la plupart des implémentations à usage général sont désormais si riches en fonctionnalités qu'il est devenu impossible de ne pas utiliser le retour arrière. Donc, en théorie, ils devraient être extrêmement (exponentiellement) lents dans certains cas. Mais pour la plupart de ces cas, des optimisations spéciales sont intégrées dans le filtreur de motifs.
Robert
0

La quantification gourmande implique une correspondance de modèle en utilisant tous les caractères non validés restants d'une chaîne au cours d'une itération. Les caractères non validés commencent dans la séquence active . Chaque fois qu'une correspondance ne se produit pas, le caractère à la fin est mis en quarantaine et la vérification est effectuée à nouveau.

Lorsque seules les conditions principales du modèle d'expression régulière sont satisfaites par la séquence active, une tentative est effectuée pour valider les conditions restantes par rapport à la quarantaine. Si cette validation réussit, les caractères correspondants dans la quarantaine sont validés et les caractères résiduels non correspondants restent non validés et seront utilisés lorsque le processus recommencera lors de l'itération suivante.

Le flux de caractères va de la séquence active à la quarantaine. Le comportement résultant est que la plus grande partie possible de la séquence d'origine est incluse dans une correspondance.

La quantification réticente est essentiellement la même que la qualification gourmande, sauf que le flux de caractères est le contraire - c'est-à-dire qu'ils commencent dans la quarantaine et se jettent dans la séquence active . Le comportement résultant est que le moins possible de la séquence d'origine est incluse dans une correspondance.

La quantification possessive n'a pas de quarantaine et inclut tout dans une séquence active fixe .

Chad Philip Johnson
la source