Gourmand vs Réticents vs Possessif Quantificateurs
J'ai trouvé ce excellent tutoriel sur les expressions régulières et alors que je intuitivement comprendre ce qu'est "gourmand", "réticents" et "possessif" quantificateurs faire, 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 manger l'ensemble de la chaîne d'entrée, des lettres d'été consommé, comparateur de la sauvegarde, plus à droite de l'occurrence de "foo" a été régurgité, etc.
Malheureusement, en dépit de la belle métaphores, je ne comprends toujours pas ce qui est mangé par qui... connaissez-vous un autre tutoriel qui explique (de façon concise) comment expressions régulières fonctionnent les moteurs?
Sinon, si quelqu'un peut expliquer un peu différent du phrasé, de l'alinéa suivant, qui serait très apprécié:
Le premier exemple utilise le gourmand
quantificateur .* afin de trouver "quelque chose", zéro
ou plusieurs fois, suivi par les lettres
"f" "o" "o". Parce que le quantificateur est
gourmand, le .* partie de la
d'abord l'expression mange l'ensemble de l'entrée
chaîne de caractères. À ce stade, l'ensemble de la
l'expression ne peut pas réussir, parce que le
trois dernières lettres ("f" "o" "o") ont
déjà été consommés (par qui?). Ainsi, le matcher
lentement sauvegarde (de droite à gauche?) une lettre à la fois
jusqu'à l'apparition de l'extrême droite
"foo" a été régurgité (qu'est-ce que cela signifie?), à qui
point du match réussit et le
la recherche se termine.Le deuxième exemple, cependant, est
réticent, il commence d'abord par
longue (par qui?) "rien". Parce que "foo"
n'apparaît pas au début de la
chaîne, il est forcé d'avaler (qui hirondelles?) l'
première lettre (un "x"), qui déclenche
le premier match à 0 et 4. Notre test
harnais continue le processus jusqu'à ce que
la chaîne d'entrée est épuisé. Il
trouve un autre match à 4 et 13.Le troisième exemple, ne parvient pas à trouver un
match parce que le quantificateur est
possessif. Dans ce cas, l'ensemble de la
chaîne d'entrée est consommée par l' .*+, (comment?)
ne laissant rien pour satisfaire
le "toto" à la fin de la
de l'expression. Utiliser un possessif
quantificateur pour les situations où vous
voulez vous emparer de tous quelque chose sans
jamais reculer (ce n'back off signifie?); il sera mieux
l'équivalent gourmand quantificateur dans
les cas où le match n'est pas
immédiatement trouvé.
- Maximale des quantificateurs comme
*
,+
, et?
sont gourmand. un Minimum de quantificateurs comme*?
,+?
, et??
sont paresseux. Possessif des quantificateurs comme*+
,++
, et?+
sont collant. - Cette question a été ajoutée à la Débordement de Pile dans l'Expression Régulière de la FAQ, sous "Quantificateurs > en savoir Plus sur les différences...".
Vous devez vous connecter pour publier un commentaire.
Je vais donner un coup de feu.
Un gourmand quantificateur premiers matchs autant que possible. Ainsi, le
.*
correspond à l'ensemble de la chaîne. Puis le comparateur essaie de faire correspondre lesf
suivants, mais il n'y a pas de caractères à gauche. Donc, il "revient", faire le gourmand quantificateur correspondre à une chose de moins (en laissant le "o" à la fin de la chaîne inégalée). N'est toujours pas correspondre à laf
dans la regex, de sorte qu'il "revient" un pas de plus, en faisant le gourmand quantificateur correspondre à une chose de moins à nouveau (en laissant le "oo" à la fin de la chaîne inégalée). Que encore ne correspond pas à laf
dans la regex, de sorte qu'il revient d'un pas de plus (en laissant le "toto" à la fin de la chaîne inégalée). Maintenant, le matcher correspond finalement lef
dans la regex, et lao
et la prochaineo
sont appariés trop. Succès!Un réticents ou "non-greedy" quantificateur premiers matchs aussi peu que possible. Ainsi, le
.*
correspond à rien à la première, laissant l'ensemble de la chaîne inégalée. Puis le comparateur essaie de faire correspondre lesf
la suite, mais l'incomparable partie de la chaîne de caractères commence par un "x" si cela ne fonctionne pas. Ainsi, le comparateur de revient, faisant de la non-greedy quantificateur match encore une chose (maintenant, il correspond à "x", laissant "fooxxxxxxfoo" inégalée). Puis il essaie de faire correspondre lef
, qui réussit, et leo
et la prochaineo
dans la regex match de trop. Succès!Dans votre exemple, il commence alors le processus avec le reste inégalée partie de la chaîne, en suivant le même processus.
Un possessif quantificateur est comme le gourmand quantificateur, mais il ne veut pas revenir en arrière. Donc ça commence avec
.*
correspondant à la totalité de la chaîne, ne laissant rien inégalée. Ensuite, il ne reste rien pour elle pour la faire correspondre avec laf
dans la regex. Depuis le possessif quantificateur ne pas revenir en arrière, le match ne parvient pas là..*+
(notez le "+").*+
qui correspond à tout. Par exemple, si vous avez un modèle[xyz]*foo
, il n'y a aucun moyen qu'un recul de l'x, y, et z est compensée par la[xyz]*
bits ne jamais permettre aufoo
peu de match, de sorte que vous pouvez accélérer les choses en faisant possessive.C'est juste ma pratique de sortie à visualiser la scène-
Je n'ai pas entendu les termes exacts 'régurgiter" ou "reculer" avant; l'expression à remplacer ces "retours en arrière", mais "régurgiter" semble aussi bon qu'une phrase comme tout pour "le contenu qui avait été provisoirement acceptée avant de mandature a jeté de nouveau".
La chose importante à réaliser sur la plupart des regex moteurs est qu'ils sont mandature: ils provisoirement accepter un potentiel, correspondance partielle, tout en essayant de correspondre à la totalité du contenu de la regex. Si la regex ne peut pas être complètement correspondait à la première tentative, puis le moteur d'expressions régulières seront backtrack sur l'un de ses matches. Il va essayer de correspondance
*
,+
,?
, alternance, ou{n,m}
répétition différemment, et essayez à nouveau. (Et oui, ce processus peut prendre un certain temps.)Les trois dernières lettres,
f
,o
, eto
étaient déjà consommés par les premiers.*
partie de la règle. Cependant, l'élément suivant dans la regex,f
, n'a rien laissé dans la chaîne d'entrée. Le moteur sera forcé de backtrack sur son premier.*
match, et essayer de faire correspondre tous-mais-le-dernier caractère. (Il pourrait être smart et revenir en arrière pour tous-mais-le-dernier-trois, parce qu'il a trois sens littéral du terme, mais je suis pas au courant des détails de mise en œuvre à ce niveau.)Cela signifie que le
foo
avait provisoirement été, y compris lors de l'appariement des.*
. Parce que l'échec de cette tentative, le moteur d'expressions régulières essaie d'accepter moins de caractère dans.*
. S'il y avait eu un match de succès avant la.*
dans cet exemple, le moteur serait probablement essayer de raccourcir le.*
match (de droite à gauche, comme vous l'avez souligné, parce que c'est un gourmand qualifier), et si elle était incapable de répondre à l'ensemble des entrées, alors il pourrait être forcé de réévaluer ce qu'il avait été à la hauteur avant la.*
dans mon exemple hypothétique.La première, rien n'est consommé par
.?*
, qui va consommer le plus possible le montant de tout ce qui permet au reste de la regex de match.De nouveau le
.?*
consomme le premier caractère, après de revenir sur l'échec initial pour correspondre à l'ensemble de la regex avec la plus courte possible. (Dans ce cas, le moteur d'expressions régulières est d'étendre le match pour.*?
de gauche à droite, parce que.*?
est réticent à le faire.)Un
.*+
consomment autant que possible, et ne sera pas revenir en arrière à trouver de nouveaux matches lors de la regex ne parvient pas à trouver une correspondance. Parce que la forme possessive de ne pas effectuer de retour en arrière, vous n'aurez probablement pas voir de nombreuses utilisations avec.*+
, mais plutôt avec des classes de personnages ou des restrictions semblables:account: [[:digit:]]*+ phone: [[:digit:]]*+
.Cela peut considérablement accélérer les regex correspondance, parce que vous dites que le moteur d'expressions régulières qu'il ne faut jamais revenir en arrière sur les correspondances possibles si une entrée ne correspond pas. (Si vous aviez à écrire tout le code correspondant à la main, ce serait semblable à jamais à l'aide de
putc(3)
à "repousser" une entrée de caractères. Il serait très semblable à de la naïveté de code on peut écrire sur un premier essai. Sauf regex moteurs sont bien meilleur que d'un seul caractère de push-back, ils peuvent rewind toutes les remises à zéro et essayer de nouveau. 🙂Mais plus élevé que le potentiel de vitesse de l'onduleur, cela peut aussi vous permettent d'écrire des regexs qui correspondent exactement ce dont vous avez besoin pour correspondre. Je vais avoir du mal à trouver un exemple facile 🙂 mais l'écriture d'une expression régulière en utilisant possessif vs gourmand quantificateurs peuvent vous donner des matches différents, et l'un ou l'autre peut être plus approprié.
"Sauvegarde" dans ce contexte signifie "retour en arrière" -- jeter une tentative de correspondance partielle d'essayer une autre correspondance partielle, qui peut ou peut ne pas réussir.
http://swtch.com/~rsc/regexp/regexp1.html
Je ne suis pas sûr que la meilleure explication sur l'internet, mais c'est assez bien écrit et suffisamment détaillé, et je reviens toujours à elle. Vous pourriez vouloir vérifier.
Si vous voulez un plus haut niveau (moins l'explication détaillée), pour les expressions régulières simples comme celui que vous êtes en train de regarder, un moteur d'expression régulière œuvres par les retours en arrière. Essentiellement, il choisit ("mange"), une section de la corde et tente de faire correspondre l'expression régulière à l'encontre de cette section. Si elle correspond, grand. Si pas, le moteur modifie son choix de la section de la corde et tente de faire correspondre les regexp à l'encontre de cette section, et ainsi de suite, jusqu'à ce qu'il est essayé de chaque choix possible.
Ce processus est utilisé de manière récursive: dans sa tentative de faire correspondre une chaîne avec une expression régulière donnée, le moteur va diviser l'expression régulière en morceaux et appliquer l'algorithme pour chaque pièce individuellement.
La différence entre le gourmand, réticents, et les quantificateurs possessifs entre quand le moteur est son choix de quelle partie de la chaîne à essayer de faire correspondre, et comment modifier ce choix si cela ne fonctionne pas la première fois. Les règles sont comme suit:
Une gourmande quantificateur indique au moteur de démarrer avec le ensemble chaîne (ou au moins, tout ce qui n'a pas déjà été appariés par les parties précédentes de l'expression régulière) et vérifier qu'il correspond à l'expression rationnelle. Si oui, les grands, le moteur peut continuer avec le reste de la regexp. Si pas, il essaie à nouveau, mais le parage d'un caractère (la dernière) au large de la section de la chaîne à être vérifié. Si cela ne fonctionne pas, il retire un autre personnage, etc. Ainsi, un gourmand quantificateur vérifie les correspondances possibles dans l'ordre de la plus longue à la plus courte.
Un peu réticents quantificateur indique au moteur de démarrer avec la plus courte possible morceau de la chaîne. Si elle correspond, le moteur peut continuer; sinon, il ajoute d'un caractère vers la section de la chaîne en cours de vérification et qui tente, et ainsi de suite jusqu'à ce qu'il trouve une correspondance ou la totalité de la chaîne a été utilisé. Donc un peu réticents quantificateur vérifie les correspondances possibles dans l'ordre, de la plus courte à la plus longue.
Un possessif quantificateur est comme une gourmande quantificateur à la première tentative: il indique au moteur à commencer par la vérification de l'ensemble de la chaîne. La différence est que si ça ne fonctionne pas, le possessif quantificateur rapports que le match n'a pas à droite, puis et là. Le moteur ne change pas la section de la chaîne d'être regardé, et il ne faut pas faire plus de tentatives.
C'est pourquoi le possessif quantificateur match échoue dans votre exemple: la
.*+
obtient vérifié par rapport à la totalité de la chaîne, qui elle correspond, mais le moteur continue de chercher de nouveaux personnagesfoo
après que - mais bien sûr, il ne les trouve pas, parce que vous êtes déjà à la fin de la chaîne. Si c'était un gourmand quantificateur, il serait revenir en arrière et essayer de faire le.*
seul match jusqu'à l'avant-dernier caractère, puis jusqu'à la troisième à la dernière lettre, puis jusqu'à la quatrième à la dernière lettre, qui réussit, car alors seulement est-il unfoo
à gauche après le.*
a "mangé" la partie antérieure de la chaîne.Ici est mon point de vue en utilisant la Cellule et les positions d'Index (Voir la schéma ici de distinguer une Cellule à partir d'un Index).
Gourmand - Correspondre autant que possible à cause de la cupidité des quantificateurs et de l'ensemble de la regex. Si aucune correspondance n'est trouvée, revenir en arrière sur le gourmand quantificateur.
Chaîne d'entrée: xfooxxxxxxfoo
Regex: .*foo
Ci-dessus Regex a deux parties:
(i)'.*'
(ii)'foo'
Chacune des étapes ci-dessous permettra d'analyser les deux parties. Commentaires additionnels pour un match de "Pass" ou "Fail" est expliqué à l'intérieur des accolades.
Étape 1:
(i) .* = xfooxxxxxxfoo - PASS ('.*' est une gourmande quantificateur, et d'utiliser la totalité de la Chaîne d'Entrée)
(ii) foo = Pas de caractère à la gauche du match après l'indice 13 - ÉCHEC
Match n'a pas.
Étape 2:
(i) .* = xfooxxxxxxfo - PASS (de revenir sur les gourmand quantificateur '.*')
(ii) foo = o - ÉCHEC
Match n'a pas.
Étape 3:
(i) .* = xfooxxxxxxf - PASS (de revenir sur les gourmand quantificateur '.*')
(ii) foo = oo FAIL
Match n'a pas.
Étape 4:
(i) .* = xfooxxxxxx - PASS (de revenir sur les gourmand quantificateur '.*')
(ii) foo = foo - PASS
Rapport de MATCH
Résultat: 1 match(es)
J'ai trouvé le texte "xfooxxxxxxfoo" commençant à l'index 0 et se terminant à l'indice 13.
Réticents Match aussi peu que possible à la réticence des quantificateurs et correspondre à l'ensemble de la regex. si aucune correspondance n'est trouvée, ajouter des caractères à la réticence des quantificateurs.
Chaîne d'entrée: xfooxxxxxxfoo
Regex: .*?foo
Au-dessus de la regex est en deux parties:
(i)".*?'
(ii) 'foo'
Étape 1:
.*? = " (vide) - PASS (Match aussi peu que possible pour les réticents quantificateur '.*?'. Indice 0 ayant " est un match.)
foo = xfo - FAIL (Cellule 0,1,2 - je.e indice entre 0 et 3)
Match n'a pas.
Étape 2:
.*? = x - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. La cellule 0 ayant un 'x' est un match.)
foo = foo - PASS
Rapport de MATCH
Étape 3:
.*? = " (vide) - PASS (Match aussi peu que possible pour les réticents quantificateur '.*?'. Indice 4 " est un match.)
foo = xxx - FAIL (Cellule 4,5,6 - je.e indice entre 4 et 7)
Match n'a pas.
Étape 4:
.*? = x - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. Cellule 4.)
foo = xxx - FAIL (Cellule 5,6,7 - je.e indice entre 5 et 8)
Match n'a pas.
Étape 5:
.*? = xx - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. La cellule de 4 à 5.)
foo = xxx - FAIL (Cellule 6,7,8 - je.e indice entre 6 et 9).
Match n'a pas.
Étape 6:
.*? = xxx - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. Cellule 4 à 6).)
foo = xxx - FAIL (Cellule 7,8,9 - je.e indice entre 7 et 10)
Match n'a pas.
Étape 7:
.*? = xxxx - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. Cellule 4 thru 7.)
foo = xxf - FAIL (Cellule 8,9,10 - je.e indice entre 8 et 11)
Match n'a pas.
Étape 8:
.*? = xxxxx - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. La cellule de 4 à 8.)
foo = xfo - FAIL (Cellule 9,10,11 - je.e indice entre 9 et 12)
Match n'a pas.
Étape 9:
.*? = xxxxxx - PASS (Ajouter des caractères à la réticence des quantificateurs '.*?'. Cellule 4 à 9.)
foo = foo - PASS (Cellule 10,11,12 - je.e indice entre 10 et 13)
Rapport de MATCH
Étape 10:
.*? = " (vide) - PASS (Match aussi peu que possible pour les réticents quantificateur '.*?'. Index 13 est vide.)
foo = Pas de caractère à la gauche du match de l'ÉCHEC (Il n'y a rien après l'indice 13 pour correspondre)
Match n'a pas.
Résultat: 2 match(es)
J'ai trouvé le texte "xfoo" commençant à l'index 0 et se terminant à l'indice 4.
J'ai trouvé le texte "xxxxxxfoo" commençant à l'index 4 et se terminant à l'indice 13.
Possessif - Correspondre autant que possible à l'possessif quantifer et correspondre à l'ensemble de la regex. Ne PAS faire marche arrière.
Chaîne d'entrée: xfooxxxxxxfoo
Regex: .*+foo
Au-dessus de la regex est en deux parties: '.*+' et 'foo'.
Étape 1:
.*+ = xfooxxxxxxfoo - PASS (Correspondre autant que possible à l'possessif quantificateur '.*')
foo = Pas de caractère à la gauche de match - FAIL (Rien de match après l'indice 13)
Match n'a pas.
Remarque: retour en arrière n'est pas autorisé.
Résultat: 0 match(es)
Gourmand: "le match le plus longtemps possible de la séquence de caractères"
Réticents: "le match le plus rapidement possible de la séquence de caractères"
Possessif: C'est un peu étrange car il n'est PAS (contrairement à gourmand et réticent) essayer de trouver une correspondance pour l'ensemble de la regex.
Par la voie: Pas de regex modèle comparateur de mise en œuvre utilisera jamais de retours en arrière. Tous les de la vie réelle modèle de correspondance sont extrêmement rapides - presque indépendante de la complexité de l'expression régulière!
Gourmand Quantification implique la correspondance de motif à l'aide de tous les autres non validées caractères d'une chaîne au cours d'une itération. Non validés début de personnages dans le séquence active. Chaque fois qu'un match ne se produit pas, le personnage à la fin est mis en quarantaine et la vérification est effectuée de nouveau.
Lorsque que leader des conditions de l'expression régulière pattern sont satisfaits par la séquence active, une tentative est faite pour valider les conditions restantes à l'encontre de la quarantaine. Si cette validation est réussie, caractères correspondent à la mise en quarantaine sont validés et résiduelles non compensées caractères restent non validée et sera utilisé lorsque le processus recommence à la prochaine itération.
Le flux de caractères est à partir de la séquence active dans la quarantaine. Le comportement qui en résulte, c'est que comme beaucoup de la séquence d'origine est inclus dans un match que possible.
Réticents Quantification est essentiellement le même que gourmand de qualification à l'exception du flux de caractères est le contraire-qui est, ils commencent à la quarantaine et le débit dans le séquence active. Le comportement qui en résulte est que peu de la séquence d'origine est inclus dans un match que possible.
Possessif Quantification ne dispose pas d'un quarantaine et inclut tout ce qui est fixé par le séquence active.