La référence faisant autorité sur les problèmes pragmatiques derrière la mise en œuvre des moteurs regex est une série de trois articles de blog de Russ Cox . Comme décrit ici, étant donné que les références arrières rendent votre langue non régulière, elles sont implémentées en utilisant le retour arrière .
Les lookaheads et lookbehinds, comme de nombreuses fonctionnalités des moteurs de recherche de motifs d'expression régulière, ne correspondent pas tout à fait au paradigme de décider si une chaîne est membre d'une langue ou non. Plutôt avec des expressions rationnelles, nous recherchons généralement des sous-chaînes dans une chaîne plus grande. Les "correspondances" sont des sous-chaînes qui sont membres du langage, et la valeur de retour correspond aux points de début et de fin de la sous-chaîne dans la chaîne plus grande.
Le point de lookaheads et lookbehinds n'est pas tant d'introduire la possibilité de faire correspondre des langues non régulières, mais plutôt d'ajuster où le moteur signale les points de début et de fin de la sous-chaîne correspondante.
Je m'appuie sur la description à http://www.regular-expressions.info/lookaround.html . Les moteurs regex qui prennent en charge cette fonctionnalité (Perl, TCL, Python, Ruby, ...) semblent tous être basés sur le backtracking (c'est-à-dire qu'ils prennent en charge un ensemble de langues beaucoup plus large que les langues normales). Ils semblent implémenter cette fonctionnalité comme une extension relativement "simple" du retour arrière, plutôt que d'essayer de construire de vrais automates finis pour effectuer la tâche.
Lookahead positif
La syntaxe de l' anticipation positive est l' (?=
expression régulière)
. Ainsi, par exemple q(?=u)
, q
ne correspond que s'il est suivi de u
, mais ne correspond pas à u
. J'imagine qu'ils implémentent cela avec une variation sur le retour en arrière. Créez un FSM pour l'expression avant l'anticipation positive. Lorsque ces correspondances se souviennent de l'endroit où elles se sont terminées et démarrent un nouveau FSM qui représente l'expression à l'intérieur de l'anticipation positive. Si cela correspond alors vous avez une "correspondance", mais la correspondance "se termine" juste avant la position où la correspondance positive a commencé.
La seule partie de cela qui serait difficile sans retour en arrière est que vous devez vous rappeler le point dans l'entrée où commence la recherche et déplacer votre bande d'entrée vers cette position après avoir terminé la correspondance.
Lookahead négatif
La syntaxe de l'anticipation négative est l' (?!
expression régulière)
. Ainsi, par exemple q(?!u)
, q
ne correspond que s'il n'est pas suivi u
. Cela peut être soit un q
suivi d'un autre caractère, soit un tout q
à la fin de la chaîne. J'imagine que cela est mis en œuvre en créant un NFA pour l'expression d'anticipation, puis en ne réussissant que si le NFA ne correspond pas à la chaîne suivante.
Si vous voulez le faire sans compter sur le retour en arrière, vous pouvez annuler le NFA de l'expression de l'anticipation, puis traitez-le de la même manière que vous traitez l'anticipation positive.
Lookbehind positif
(?<=
)
(?=q)u
u
q
q
nnn
Vous pourriez être en mesure d'implémenter cela sans retour en arrière en prenant l'intersection de "chaîne qui se termine par regex " avec n'importe quelle partie de l'expression régulière qui précède l'opérateur lookbehind. Cela va cependant être délicat, car l' expression rationnelle derrière peut avoir besoin de regarder plus en arrière que le début actuel de l'entrée.
Lookbehind négatif
La syntaxe pour lookbehind négatif est (?<!
regex)
. Ainsi, par exemple, (?<!q)u
correspond u
, mais uniquement s'il n'est pas précédé de q
. Cela correspondrait donc à l' u
entrée umbrella
et à l' u
entrée doubt
, mais pas à l' u
entrée quick
. Encore une fois, cela semble être fait en calculant la longueur de l' expression régulière , en sauvegardant autant de caractères, en testant la correspondance avec l' expression régulière , mais en échouant maintenant toute la correspondance si le lookbehind correspond.
Vous pourriez être en mesure de mettre en œuvre cela sans retour en arrière en prenant la négation de l' expression régulière , puis en faisant de même que vous le feriez pour un lookbehind positif.