78 votes

Ne lookaround affecter les langues peuvent être obtenues par les expressions régulières?

Il y a certaines caractéristiques modernes de la regex de moteurs qui permettent de faire correspondre les langues qui n'a pas pu être appariés sans cette fonctionnalité. Par exemple, la regex suivante à l'aide de références arrière correspond à la langue de toutes les chaînes qui est composée d'un mot qui se répète: (.+)\1. Cette langue n'est pas régulière et ne peut être égalé par une expression régulière qui n'utilise pas les références arrières.

Ne lookaround également affecter les langues correspondant à une expression régulière? I. e. existe-il des langues qui peuvent être appariés en utilisant lookaround qui n'a pas pu être appariés autrement? Si oui, est-ce vrai pour tous les types de lookaround (négative ou positive d'anticipation ou lookbehind) ou seulement pour certains d'entre eux?

27voto

Francis Davey Points 542

La réponse à la question que vous posez, qui est de savoir si une classe plus large de langues que les langues peuvent être reconnus avec des expressions régulières augmentée par lookaround, n'est pas.

Une preuve en est relativement simple, mais un algorithme pour traduire une expression régulière contenant lookarounds dans l'une sans est en désordre.

Première: notez que vous pouvez toujours annuler une expression régulière (sur un alphabet fini). Étant donné un graphe d'état de l'automate qui reconnaît le langage généré par l'expression, vous pouvez simplement échanger tous les acceptant les états de non-acceptation des états pour obtenir un FSA, qui reconnaît exactement la négation de cette langue, pour lesquels il existe une famille de l'équivalent des expressions régulières.

Deuxièmement: parce que les langages réguliers (et donc des expressions régulières) sont fermés en vertu de la négation ils sont également fermé en vertu de l'intersection depuis Une intersection B = neg ( neg(A) de l'union neg(B)) par de Morgan lois. En d'autres mots, deux expressions régulières, vous pouvez trouver une autre expression régulière qui correspond à la fois.

Cela vous permet de simuler lookaround expressions. Par exemple, u(?=v)w correspond seulement les expressions qui correspondent aux uv et à l'université du wisconsin.

Pour d'anticipation négatif, vous avez besoin de l'expression régulière équivalente de l'ensemble de la théorie des A\B, qui est juste Un intersect (neg B) ou, de manière équivalente neg (neg(A) de l'union B). Ainsi pour tous les regular expressions r et s, vous pouvez trouver une expression régulière r-s qui correspond à ces expressions qui correspondent à r, ce qui ne correspond pas à s. En anticipation négatif termes: u(?!v)w correspond seulement les expressions qui correspondent à uw - uv.

Il y a deux raisons pour lesquelles lookaround est utile.

D'abord, parce que la négation d'une expression régulière peut entraîner dans quelque chose de beaucoup moins bien rangé. Par exemple q(?!u)=q($|[^u]).

Deuxièmement, les expressions régulières en faire plus que les expressions de correspondance, ils consomment aussi des caractères d'une chaîne - ou du moins c'est la façon dont nous aimons à penser à eux. Par exemple en python je me soucie de la .start() et .end(), donc bien sûr:

>>> re.search('q($|[^u])', 'Iraq!').end()
5
>>> re.search('q(?!u)', 'Iraq!').end()
4

Troisièmement, et je pense que c'est plutôt une raison importante, la négation des expressions régulières ne soulevez pas bien sur la concaténation. neg(a)neg(b) n'est pas la même chose que neg(ab), ce qui signifie que vous ne pouvez pas traduire un lookaround hors du contexte dans lequel vous le trouvez - vous avez à traiter de l'ensemble de la chaîne. Je suppose que ça le rend désagréable pour les gens à travailler et les pauses de la réaction des gens sur des expressions régulières.

J'espère avoir répondu à votre question théorique (ses tard dans la nuit, donc pardonnez-moi si je suis pas clair). Je suis d'accord avec le commentateur qui a dit que ce n'est avoir des applications pratiques. J'ai rencontré beaucoup le même problème lorsque vous essayez de gratter quelques très compliqué de pages web.

MODIFIER

Mes excuses pour ne pas être plus clair: je ne crois pas que vous pouvez donner une preuve de la régularité des expressions régulières + lookarounds par induction structurelle, mon u(?!v)w exemple était censé être juste que, un exemple, et facile. La raison structurelle de l'induction ne fonctionne pas est parce que lookarounds se comporter dans un non-composition: le point que j'essayais de faire au sujet des négations ci-dessus. Je soupçonne directe de la preuve formelle va avoir beaucoup de problèmes. J'ai essayé de penser à un moyen facile de le montrer, mais ne peut pas venir avec un arrêt sur le dessus de ma tête.

Pour illustrer, à l'aide de Josh premier exemple d' ^([^a]|(?=..b))*$ c'est l'équivalent de 7 état DONNE à tous les états d'accepter:

A - (a) -> B - (a) -> C --- (a) --------> D 
Λ          |           \                  |
|          (not a)       \               (b)
|          |              \               | 
|          v                \             v
(b)        E - (a) -> F      \-(not(a)--> G  
|            <- (b) - /                   |
|          |                              |
|         (not a)                         |
|          |                              |
|          v                              |
\--------- H <-------------------(b)-----/

L'expression régulière de l'état d'Un seul ressemble:

^(a([^a](ab)*[^a]|a(ab|[^a])*b)b)*$

En d'autres termes, toute expression régulière que vous allez obtenir en éliminant lookarounds sera en général beaucoup plus long et beaucoup de messier.

Pour répondre à Josh commentaire - oui, je pense que le moyen le plus direct pour prouver l'équivalence est par l'intermédiaire de la FSA. Ce qui rend cette messier, c'est que la manière habituelle de construire un FSA est par l'intermédiaire d'un non-déterministe de la machine - son beaucoup plus facile d'exprimer u|v en tant que tout simplement la machine construite à partir de machines pour u et v avec un epsilon de transition pour les deux d'entre eux. Bien sûr, cela est équivalent à une machine déterministe, mais au risque de l'exponentielle de blow-up de l'état. Alors que la négation est beaucoup plus facile de le faire via une machine déterministe.

La preuve générale implique de prendre le produit cartésien de deux machines et de la sélection de ces états que vous souhaitez conserver à chaque point que vous souhaitez insérer un lookaround. L'exemple ci-dessus illustre ce que je veux dire, dans une certaine mesure.

Mes excuses pour ne pas fournir d'une construction.

MODIFIER: J'ai trouvé un blog qui décrit un algorithme pour la génération d'une TFD d'une expression régulière augmentée avec lookarounds. Sa propre car l'auteur s'étend à l'idée d'une NFA-e avec "marqué epsilon-transitions" dans la manière évidente, puis explique comment convertir un tel automate dans un DFA.

J'ai pensé quelque chose comme cela serait une façon de le faire, mais je suis heureux que quelqu'un l'a écrit. Il était au-delà de moi, de venir avec quelque chose de si pur.

9voto

Josh Haberman Points 2289

Je suis d'accord avec les autres postes que lookaround est régulière (ce qui signifie qu'il n'ajoute pas les fondamentaux de la capacité à les expressions régulières), mais j'ai un argument qui est plus simple de l'OMI, de l'autre ceux que j'ai vu.

Je vais montrer que lookaround est régulièrement en fournissant un DFA de la construction. Un langage est régulier si et seulement si elle a un DFA qui le reconnaît. Notez que Perl n'est pas réellement utiliser DFAs en interne (voir ce document pour plus de détails: http://swtch.com/~rsc/regexp/regexp1.htmlmais nous n'avons construire un DFA, pour les fins de la preuve.

La manière traditionnelle de la construction d'un DFA pour une expression régulière est de construire d'abord un ADN à l'aide de l'Algorithme de Thompson. Étant donné deux expressions régulières fragments r1 et r2, Thompson Algorithme fournit la de constructions pour la concaténation (r1r2), alternance (r1|r2), et de la répétition (r1*) des expressions régulières. Cela vous permet de construire une NFA, bit par bit, qui reconnaît l'origine de l'expression régulière. Voir le document ci-dessus pour plus de détails.

Pour montrer que positifs et négatifs d'anticipation sont réguliers, je vais donner une construction pour la concaténation d'une expression régulière u positifs ou négatifs d'anticipation: (?=v) ou (?!v). Seulement concaténation nécessite un traitement spécial; l'habitude de l'alternance et de la répétition des constructions, beau travail.

La construction est à la fois u(?=v) et u(?!v) est:

http://imgur.com/ClQpz.png

En d'autres mots, vous connecter chaque état final de l'existant NFA pour u à la fois à l'état et à un ADN pour v, mais elle est modifiée comme suit. La fonction f(v) est défini comme:

  • Laissez - aa(v) être une fonction sur un NFA v qui change tous les accepter dans un "anti-accepter de l'état". Un anti-accepter de l'état est défini comme un état qui provoque le match à l'échec si aucun chemin d'accès par le biais de la NFA se termine dans cet état pour une chaîne donnée en s, même si un autre chemin à travers l' v pour s se termine dans l'état.
  • Laissez - loop(v) être une fonction sur un NFA v qui ajoute une transition sur tout accepter de l'état. En d'autres termes, une fois qu'un chemin mène à accepter un état, ce chemin peut rester dans l'accepter état actuel des choses, peu importe ce que l'entrée de la façon suivante.
  • Pour le négatif, d'anticipation, f(v) = aa(loop(v)).
  • Pour d'anticipation positif, f(v) = aa(neg(v)).

Pour donner un exemple intuitif pour expliquer pourquoi cela fonctionne, je vais utiliser les regex (b|a(?:.b))+, qui est une version légèrement simplifiée de la regex que j'ai proposée dans les commentaires de François de la preuve. Si nous utilisons ma construction avec le traditionnel Thompson constructions, nous nous retrouvons avec:

alt text

L' es sont epsilon-transitions (transitions qui peuvent être prises sans consommer d'entrée) et de l'anti-accepter les états sont étiquetés avec un X. Dans la moitié gauche du graphique que vous voyez la représentation de l' (a|b)+: tout a ou b met le graphique de l'état, mais permet également à un retour à la commencer état, de sorte que nous pouvons le faire à nouveau. Mais notez que chaque fois que nous faisons correspondre un a nous aussi entrer dans la moitié droite du graphique, où nous sommes dans l'anti-accepter les états jusqu'à ce que nous match "tout", suivi par un b.

Ce n'est pas un traditionnel NFA parce que les Fan n'ont pas d'anti-accepter les états. Cependant, nous pouvons utiliser la traditionnelle NFA->DFA algorithme afin de le convertir en un traditionnel DFA. L'algorithme fonctionne comme d'habitude, où nous simuler de multiples pistes de la convention, en faisant de nos DFA états correspondent à des sous-ensembles de la NFA états que l'on pourrait avoir. Le seul hic, c'est que nous avons légèrement augmenter la règle pour décider si une TFD de l'état est un accept (final) de l'état ou pas. Dans la tradition de l'algorithme d'un DFA état est l'état si tout de la NFA unis est d'accepter de l'état. Nous de modifier cela pour dire qu'un DFA état est l'état si et seulement si:

  • >= 1 NFA unis est l'état, et
  • 0 NFA états sont anti-accepter les états.

Cet algorithme va nous donner un DFA qui reconnaît l'expression régulière avec d'anticipation. Ergo, d'anticipation est régulier. Notez que lookbehind exige une preuve distincte.

2voto

NealB Points 11102

J'ai le sentiment qu'il y a deux questions distinctes être posée ici:

  • Sont Regex moteurs encorporate "lookaround" plus puissant que la Regex de moteurs qui ne le font pas?
  • N' "lookaround" responsabiliser un moteur d'expressions régulières avec la capacité d'analyser les langues plus complexes que ceux générés à partir d'un Chomsky Type 3 - Régulier de la grammaire?

La réponse à la première question dans un sens pratique est oui. Lookaround donnera un moteur d'expressions régulières qui utilise cette caractéristique fondamentalement plus de pouvoir que celui qui ne l'est pas. C'est parce que il fournit un ensemble plus riche de "ancres" pour le processus d'appariement. Lookaround permet de définir un ensemble de Regex comme un possible point d'ancrage (largeur nulle affirmation). Vous pouvez obtenir un assez bon aperçu de la puissance de cette fonctionnalité ici.

Lookaround, bien que puissant, ne soulevez pas le moteur d'expressions régulières au-delà de la théorique les limites imposées par un Type 3 de Grammaire. Par exemple, vous ne serez jamais en mesure de manière fiable l'analyse grammaticale d'une langue basée sur un Contexte Libre de Type 2 de Grammaire à l'aide d'un moteur d'expressions régulières équipé avec lookaround. Regex moteurs sont limités à la puissance d'un État Fini d'Automatisation et fondamentalement restreint l'expressivité de n'importe quelle langue ils peuvent analyser le niveau d'un Type 3 de Grammaire. Peu importe combien de "trucs" sont ajoutés à votre moteur d'expressions régulières, les langues généré par une Grammaire sans Contexte restera toujours au-delà de ses capacités. L'analyse du Contexte de Libre - Type 2 grammaire exige de refoulement de l'automatisation de "se souvenir" où il est en récursive de construction du langage. Tout ce qui nécessite une évaluation récursive des règles de grammaire ne peut pas être analysé à l'aide de Regex moteurs.

Pour résumer: Lookaround offre certains avantages pratiques de Regex moteurs, mais ne pas "perturber le jeu" sur un niveau théorique.

MODIFIER

Est-il une grammaire avec une complexité quelque part entre le Type 3 (Normal) et de Type 2 (sans Contexte)?

Je crois que la réponse est non. La raison en est parce qu'il n'y a pas de limite théorique placé sur la taille de la NFA/DFA nécessaires pour décrire un langage Régulier. Il peut devenir arbitrairement grand et donc impossible à utiliser (ou à spécifier). C'est là que esquives comme "lookaround" sont utiles. Ils fournir un bref mécanisme pour spécifier ce qui serait autrement conduire à de très grandes/complexe ADN/DFA les spécifications. Ils ne pas augmenter l'expressivité de Langages réguliers, ils ne font de spécifier de façon plus pratique. Une fois que vous obtenez ce point, il devient clair qu'il y a beaucoup de "caractéristiques" qui pourrait être ajouté à la Regex de moteurs pour les rendre plus utile dans un sens pratique - mais rien ne va les rendre capables d'aller au-delà de la les limites d'un langage Régulier.

La différence fondamentale entre un Régulier et un Contexte de Libre-langage est un langage Régulier ne contient pas de récursive éléments. Afin d'évaluer récursive de la langue vous avez besoin d'un Pousser Vers Le Bas De L'Automatisation "souvenez-vous" où vous êtes à la récursivité. Une NFA/DFA ne pas empiler les informations d'état ne peut donc pas gérer la récursivité. Donc, étant donné un non-récursive de définition de langage, il y aura quelques NFA/DFA (mais pas nécessairement une pratique de l'expression Regex) pour la décrire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X