Remarque: Après avoir essayé cela moi-même, j'ai vite réalisé à quel point c'était une erreur. Par conséquent, je modifie un peu les règles.
La fonctionnalité minimale requise:
- Les classes de caractères (
.
,\w
,\W
, etc.) - Multiplicateurs (
+
,*
et?
) - Groupes de capture simples
Votre défi est d'implémenter PCRE dans la langue de votre choix sous les conditions suivantes:
- Vous ne pouvez pas utiliser dans des installations RegEx natifs de votre langue toute façon . Vous ne pouvez pas non plus utiliser une bibliothèque RegEx tierce.
- Votre entrée doit implémenter autant de la spécification PCRE. que possible.
Votre programme doit accepter en entrée, 2 lignes:
- l'expression régulière
- l'entrée de chaîne à comparer
Votre programme doit indiquer dans sa sortie:
- Si le RegEx correspond à n'importe où dans la chaîne d'entrée
- Les résultats de tous les groupes de capture
Le gagnant sera l'entrée qui implémentera autant de spécifications. que possible. En cas d'égalité, le gagnant sera la participation la plus créative, selon moi.
Edit: pour clarifier quelques points, voici quelques exemples d'entrées et de sorties attendues:
- Contribution:
^ \ s * (\ w +) $ Bonjour
- Production:
Matchs: oui Groupe 1: «bonjour»
- Contribution:
(\ w +) @ (\ w +) (?: \. com | \ .net) [email protected]
- Production:
Matchs: oui Groupe 1: «sam» Groupe 2: «test»
code-challenge
regular-expression
Nathan Osman
la source
la source
Réponses:
Python
Étant donné que la mise en œuvre de PCRE complet est trop, je n'en ai implémenté qu'un sous-ensemble essentiel.
Prise en charge
|.\.\w\W\s+*()
. L'expression rationnelle d'entrée doit être correcte.Exemples:
Comment ça fonctionne:
Pour une théorie détaillée, lisez cette introduction à la théorie des automates, aux langages et au calcul .
L'idée est de convertir l'expression régulière d'origine en automates finis non déterministes (NFA). En fait, les expressions régulières PCRE sont au moins des grammaires sans contexte pour lesquelles nous avons besoin d'automates déroulants, mais nous nous limiterons à un sous-ensemble de PCRE.
Les automates finis sont des graphes dirigés dans lesquels les nœuds sont des états, les arêtes sont des transitions et chaque transition a une entrée correspondante. Au départ, vous démarrez à partir d'un nœud de démarrage, prédéfini. Chaque fois que vous recevez une entrée correspondant à l'une des transitions, vous passez cette transition à un nouvel état. Si vous avez atteint un nœud terminal, il est appelé cette entrée acceptée par les automates. Dans notre cas, l'entrée est une fonction de correspondance qui renvoie vrai.
Ils sont appelés automates non déterministes car il existe parfois plus de transitions correspondantes que vous pouvez prendre à partir du même état. Dans mon implémentation, toute transition vers le même état doit correspondre à la même chose, j'ai donc stocké la fonction correspondante avec l'état de destination (
states[dest][0]
).Nous transformons notre expression rationnelle en automates finis en utilisant des blocs de construction. Un bloc de construction a un nœud de départ (
first
) et un nœud de fin (last
) et correspond à quelque chose du texte (chaîne vide possible).Les exemples les plus simples incluent
True
(first == last
)c == txt[pos]
(first == last
)(
first == last`)Vous aurez également besoin de la nouvelle position dans le texte où faire correspondre le prochain jeton.
Des exemples plus compliqués sont (les majuscules représentent les blocs).
B + correspondant:
correspondant à A | B | C:
Tous les opérateurs d'expression rationnelle peuvent être transformés comme ceci. Essayez juste
*
.La dernière partie consiste à analyser l'expression rationnelle qui nécessite une grammaire très simple:
Espérons que la mise en œuvre d'une grammaire simple (je pense que c'est LL (1), mais corrigez-moi si je me trompe) est beaucoup plus facile que de construire un NFA.
Une fois que vous avez le NFA, vous devez revenir en arrière jusqu'à ce que vous atteigniez le nœud terminal.
Code source (ou ici ):
la source
(a+b)+
Matchs TILabaabaaabaaaab
.