Existe-t-il une expression régulière pour détecter une expression régulière valide?
1007
Est-il possible de détecter une expression régulière valide avec une autre expression régulière? Si oui, veuillez donner un exemple de code ci-dessous.
Donc, votre problème est la validation d'une expression régulière, vous avez choisi une expression régulière pour le résoudre. Je me demande si la propriété d'augmentation du nombre de problèmes des regex est additive ou multiplicative. Cela ressemble à 4 problèmes au lieu de 2 :)
abesto
15
Il existe de nombreuses notations pour les expressions régulières - certaines fonctionnalités et leurs orthographes sont communes à la plupart, certaines sont orthographiées différemment ou ne sont disponibles que dans une notation particulière. La plupart de ces notations ne sont pas "régulières" au sens grammatical normal - vous auriez besoin d'un analyseur sans contexte pour gérer l'imbrication illimitée des sous-expressions - bien que de nombreuses notations "d'expression régulière" modernes aient des extensions qui vont au-delà de la définition formelle d'origine et pourraient permettre à leurs propres notations d'être reconnues. Dans tous les cas, pourquoi ne pas simplement demander à votre bibliothèque d'expressions régulières si chaque expression régulière est valide?
Steve314
1
@bevacqua j'ai besoin de valider l'expression rationnelle dans le schéma XML. Comment puis-je le faire sans autre expression régulière?
zenden2k
3
En fait, compilez / exécutez l'expression régulière (modèle) à vérifier, sous un mécanisme de gestion des exceptions dont dispose votre langue. Ainsi, le moteur / compilateur regex du langage le vérifiera lui-même. (Cela suppose une syntaxe de base correcte pour que le programme s'exécute, mais cela peut être inclus dans la vérification en utilisant les fonctionnalités de vos langues pour évaluer la chaîne pour l'expression régulière en tant que code (éventuellement incorrect sur le plan syntaxique), ou autre.)
/^# start of string(# first group start(?:(?:[^?+*{}()[\]\\|]+# literals and ^, $| \\.# escaped characters| \[ (?: \^?\\.| \^[^\\]|[^\\^])# character classes(?:[^\]\\]+| \\.)* \]| \( (?:\?[:=!]|\?<[=!]|\?>)?(?1)?? \) # parenthesis, with recursive content| \(\? (?:R|[+-]?\d+) \) # recursive matching)(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?# quantifiers| \| # alternative)*# repeat content)# end first group
$ # end of string/
Il s'agit d'une expression régulière récursive et n'est pas prise en charge par de nombreux moteurs d'expression régulière. Ceux basés sur PCRE devraient le supporter.
.NET ne prend pas directement en charge la récursivité. (Les constructions (?1)et (?R).) La récursivité devrait être convertie en comptage des groupes équilibrés:
^# start of string(?:(?:[^?+*{}()[\]\\|]+# literals and ^, $| \\.# escaped characters| \[ (?: \^?\\.| \^[^\\]|[^\\^])# character classes(?:[^\]\\]+| \\.)* \]| \( (?:\?[:=!]| \?<[=!]| \?>| \?<[^\W\d]\w*>| \?'[^\W\d]\w*')?# opening of group(?<N>)# increment counter| \) # closing of group(?<-N>)# decrement counter)(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?# quantifiers| \| # alternative)*# repeat content
$ # end of string(?(N)(?!))# fail if counter is non-zero.
Cela validera-t-il les substitutions et les traductions?
Il validera uniquement la partie regex des substitutions et des traductions. s/<this part>/.../
Il n'est théoriquement pas possible de faire correspondre toutes les grammaires d'expressions rationnelles valides avec une expression régulière.
C'est possible si le moteur d'expression régulière prend en charge la récursivité, comme PCRE, mais cela ne peut plus vraiment être appelé des expressions régulières.
En effet, une "expression régulière récursive" n'est pas une expression régulière. Mais c'est une extension souvent acceptée des moteurs d'expression régulière ... Ironiquement, cette expression régulière étendue ne correspond pas aux expressions régulières étendues.
"En théorie, la théorie et la pratique sont les mêmes. En pratique, elles ne le sont pas." Presque tous ceux qui connaissent les expressions régulières savent que les expressions régulières ne prennent pas en charge la récursivité. Mais PCRE et la plupart des autres implémentations prennent en charge bien plus que les expressions régulières de base.
en utilisant ceci avec le script shell dans la commande grep, cela me montre une erreur. grep: Contenu invalide de {}. Je fais un script qui pourrait grep une base de code pour trouver tous les fichiers qui contiennent des expressions régulières
Ce modèle exploite une extension appelée expressions régulières récursives. Ceci n'est pas pris en charge par la saveur POSIX de l'expression régulière. Vous pouvez essayer avec le commutateur -P, pour activer la saveur regex PCRE.
Regex lui-même "n'est pas un langage régulier et ne peut donc pas être analysé par une expression régulière ..."
Cela est vrai pour les expressions régulières classiques. Certaines implémentations modernes autorisent la récursivité, ce qui en fait un langage sans contexte, bien qu'il soit quelque peu verbeux pour cette tâche.
Je vois où tu correspond []()/\. et d'autres caractères regex spéciaux. Où autorisez-vous les caractères non spéciaux? Il semble que cela correspondra ^(?:[\.]+)$, mais pas ^abcdefg$. C'est une expression rationnelle valide.
[^?+*{}()[\]\\|]correspondra à n'importe quel caractère unique, ne faisant partie d'aucune des autres constructions. Cela inclut à la fois littérale ( a- z), et certains caractères spéciaux ( ^, $, .).
Cette réponse envoie les gens dans la mauvaise direction. Ils ne devraient jamais utiliser regEx pour localiser les expressions régulières, car il ne peut pas fonctionner correctement dans tous les cas. Voir ma réponse ajoutée.
vitaly-t
1
.{,1}est inégalée. Passez aux ^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d*(?:,\d*)?\})[?+]?)?|\|)*)$correspondances. CHANGER \d+jusqu'à\d*
yunzen
4
regex par def ne devrait pas avoir de récursivité, du moins dire quelque chose comme ça dans votre réponse, votre moteur regex est probablement "trop puissant" et pas vraiment un moteur regex.
Charlie Parker
Juste une note que vous avez oublié le drapeau x
RedClover
Ce validateur semble être fait pour les expressions PCRE, mais il passera de nombreux ERE POSIX invalides. , Ils sont notamment un peu plus pointilleux dans des gammes de classe de caractères, par exemple cela est valable dans PCRE mais pas dans ERE: [a-b-c].
Pedro Gimeno
321
Peu probable.
Évaluez-le dans un try..catchou ce que votre langue propose.
Non, si vous parlez strictement d'expressions régulières et que vous n'incluez pas certaines implémentations d'expressions régulières qui sont en fait des grammaires sans contexte.
Il existe une limitation des expressions régulières qui rend impossible l'écriture d'une expression régulière qui correspond à toutes et uniquement aux expressions régulières. Vous ne pouvez pas faire correspondre des implémentations telles que des accolades qui sont appariées. Les expressions rationnelles utilisent de nombreuses constructions de ce type, prenons l' []exemple. Chaque fois qu'il y a un, [il doit y avoir une correspondance ], ce qui est assez simple pour une expression régulière "\[.*\]".
Ce qui rend impossible les expressions régulières, c'est qu'elles peuvent être imbriquées. Comment pouvez-vous écrire une expression régulière qui correspond aux crochets imbriqués? La réponse est que vous ne pouvez pas sans une expression régulière infiniment longue. Vous pouvez faire correspondre n'importe quel nombre de parenthèses imbriquées par la force brute, mais vous ne pouvez jamais faire correspondre un ensemble arbitrairement long de crochets imbriqués.
Cette capacité est souvent appelée comptage, car vous comptez la profondeur de l'imbrication. Une expression régulière par définition n'a pas la capacité de compter.
Les vraies langues régulières ne peuvent pas décider de parenthèses bien formées profondément imbriquées. Si votre alphabet contient '('et ')'le but est de décider si une chaîne de ceux-ci a une parenthèse correspondante bien formée. Comme il s'agit d'une exigence nécessaire pour les expressions régulières, la réponse est non.
Cependant, si vous assouplissez l'exigence et ajoutez une récursivité, vous pouvez probablement le faire. La raison en est que la récursivité peut agir comme une pile vous permettant de "compter" la profondeur d'imbrication actuelle en poussant sur cette pile.
Non, si vous utilisez des expressions régulières standard.
La raison en est que vous ne pouvez pas satisfaire le lemme de pompage pour les langues régulières. Les Etats lemme de pompage d' une chaîne appartenant au langage « L » est régulier s'il existe un certain nombre « N » de telle sorte que, après avoir divisé la chaîne en trois sous - chaînes x, y, z, de sorte que |x|>=1 && |xy|<=N, vous pouvez répéter yautant de fois que vous voulez et le la chaîne entière appartiendra toujours L.
Une conséquence du lemme de pompage est que vous ne pouvez pas avoir de chaînes régulières sous la forme a^Nb^Mc^N, c'est-à-dire deux sous-chaînes ayant la même longueur séparées par une autre chaîne. De toute façon, vous divisez ces chaînes en x, yet z, vous ne pouvez pas "pomper" ysans obtenir une chaîne avec un nombre différent de "a" et "c", laissant ainsi la langue d'origine. C'est le cas, par exemple, avec des parenthèses dans les expressions régulières.
Ce n'est pas une description très précise du lemme de pompage. Tout d'abord, c'est la langue entière qui peut être régulière ou non, pas une seule chaîne. Deuxièmement, c'est une condition nécessaire, mais non suffisante, à la régularité. Enfin, seules les cordes suffisamment longues sont pompables.
darij grinberg
13
Bien qu'il soit parfaitement possible d'utiliser une expression rationnelle récursive comme l'a signalé MizardX, pour ce genre de choses, il est beaucoup plus utile d'un analyseur. Les expressions rationnelles étaient à l'origine destinées à être utilisées avec des langages réguliers, étant récursives ou ayant des groupes d'équilibrage n'est qu'un patch.
Le langage qui définit les expressions rationnelles valides est en fait une grammaire sans contexte, et vous devez utiliser un analyseur approprié pour le gérer. Voici un exemple de projet universitaire d'analyse syntaxique des expressions rationnelles simples (sans la plupart des constructions). Il utilise JavaCC. Et oui, les commentaires sont en espagnol, bien que les noms de méthode soient assez explicites.
Vous pouvez soumettre l'expression rationnelle à preg_matchlaquelle retournera false si l'expression rationnelle n'est pas valide. N'oubliez pas d'utiliser le @pour supprimer les messages d'erreur:
L'exemple suivant de Paul McGuire, originaire du wiki Pyparsing, mais désormais disponible uniquement via la Wayback Machine , donne une grammaire pour analyser certaines expressions rationnelles, dans le but de renvoyer l'ensemble de chaînes correspondantes. En tant que tel, il rejette ceux qui incluent des termes de répétition illimités, comme «+» et «*». Mais cela devrait vous donner une idée de la façon de structurer un analyseur qui traiterait les re.
# # invRegex.py## Copyright 2008, Paul McGuire## pyparsing script to expand a regular expression into all possible matching strings# Supports:# - {n} and {m,n} repetition, but not unbounded + or * repetition# - ? optional elements# - [] character ranges# - () grouping# - | alternation#
__all__ =["count","invert"]from pyparsing import(Literal, oneOf, printables,ParserElement,Combine,SkipTo, operatorPrecedence,ParseFatalException,Word, nums, opAssoc,Suppress,ParseResults, srange)classCharacterRangeEmitter(object):def __init__(self,chars):# remove duplicate chars in character range, but preserve original order
seen =set()self.charset ="".join( seen.add(c)or c for c in chars if c notin seen )def __str__(self):return'['+self.charset+']'def __repr__(self):return'['+self.charset+']'def makeGenerator(self):def genChars():for s inself.charset:yield s
return genChars
classOptionalEmitter(object):def __init__(self,expr):self.expr = expr
def makeGenerator(self):def optionalGen():yield""for s inself.expr.makeGenerator()():yield s
return optionalGen
classDotEmitter(object):def makeGenerator(self):def dotGen():for c in printables:yield c
return dotGen
classGroupEmitter(object):def __init__(self,exprs):self.exprs =ParseResults(exprs)def makeGenerator(self):def groupGen():def recurseList(elist):if len(elist)==1:for s in elist[0].makeGenerator()():yield s
else:for s in elist[0].makeGenerator()():for s2 in recurseList(elist[1:]):yield s + s2
ifself.exprs:for s in recurseList(self.exprs):yield s
return groupGen
classAlternativeEmitter(object):def __init__(self,exprs):self.exprs = exprs
def makeGenerator(self):def altGen():for e inself.exprs:for s in e.makeGenerator()():yield s
return altGen
classLiteralEmitter(object):def __init__(self,lit):self.lit = lit
def __str__(self):return"Lit:"+self.lit
def __repr__(self):return"Lit:"+self.lit
def makeGenerator(self):def litGen():yieldself.lit
return litGen
def handleRange(toks):returnCharacterRangeEmitter(srange(toks[0]))def handleRepetition(toks):
toks=toks[0]if toks[1]in"*+":raiseParseFatalException("",0,"unbounded repetition operators not supported")if toks[1]=="?":returnOptionalEmitter(toks[0])if"count"in toks:returnGroupEmitter([toks[0]]*int(toks.count))if"minCount"in toks:
mincount =int(toks.minCount)
maxcount =int(toks.maxCount)
optcount = maxcount - mincount
if optcount:
opt =OptionalEmitter(toks[0])for i in range(1,optcount):
opt =OptionalEmitter(GroupEmitter([toks[0],opt]))returnGroupEmitter([toks[0]]* mincount +[opt])else:return[toks[0]]* mincount
def handleLiteral(toks):
lit =""for t in toks:if t[0]=="\\":if t[1]=="t":
lit +='\t'else:
lit += t[1]else:
lit += t
returnLiteralEmitter(lit)def handleMacro(toks):
macroChar = toks[0][1]if macroChar =="d":returnCharacterRangeEmitter("0123456789")elif macroChar =="w":returnCharacterRangeEmitter(srange("[A-Za-z0-9_]"))elif macroChar =="s":returnLiteralEmitter(" ")else:raiseParseFatalException("",0,"unsupported macro character ("+ macroChar +")")def handleSequence(toks):returnGroupEmitter(toks[0])def handleDot():returnCharacterRangeEmitter(printables)def handleAlternative(toks):returnAlternativeEmitter(toks[0])
_parser =Nonedef parser():global _parser
if _parser isNone:ParserElement.setDefaultWhitespaceChars("")
lbrack,rbrack,lbrace,rbrace,lparen,rparen = map(Literal,"[]{}()")
reMacro =Combine("\\"+ oneOf(list("dws")))
escapedChar =~reMacro +Combine("\\"+ oneOf(list(printables)))
reLiteralChar ="".join(c for c in printables if c notin r"\[]{}().*?+|")+" \t"
reRange =Combine(lbrack +SkipTo(rbrack,ignore=escapedChar)+ rbrack)
reLiteral =( escapedChar | oneOf(list(reLiteralChar)))
reDot =Literal(".")
repetition =(( lbrace +Word(nums).setResultsName("count")+ rbrace )|( lbrace +Word(nums).setResultsName("minCount")+","+Word(nums).setResultsName("maxCount")+ rbrace )|
oneOf(list("*+?")))
reRange.setParseAction(handleRange)
reLiteral.setParseAction(handleLiteral)
reMacro.setParseAction(handleMacro)
reDot.setParseAction(handleDot)
reTerm =( reLiteral | reRange | reMacro | reDot )
reExpr = operatorPrecedence( reTerm,[(repetition,1, opAssoc.LEFT, handleRepetition),(None,2, opAssoc.LEFT, handleSequence),(Suppress('|'),2, opAssoc.LEFT, handleAlternative),])
_parser = reExpr
return _parser
def count(gen):"""Simple function to count the number of elements returned by a generator."""
i =0for s in gen:
i +=1return i
def invert(regex):"""Call this routine as a generator to return all the strings that
match the input regular expression.
for s in invert("[A-Z]{3}\d{3}"):
print s
"""
invReGenerator =GroupEmitter(parser().parseString(regex)).makeGenerator()return invReGenerator()def main():
tests = r"""
[A-EA]
[A-D]*
[A-D]{3}
X[A-C]{3}Y
X[A-C]{3}\(
X\d
foobar\d\d
foobar{2}
foobar{2,9}
fooba[rz]{2}
(foobar){2}
([01]\d)|(2[0-5])
([01]\d\d)|(2[0-4]\d)|(25[0-5])
[A-C]{1,2}
[A-C]{0,3}
[A-C]\s[A-C]\s[A-C]
[A-C]\s?[A-C][A-C]
[A-C]\s([A-C][A-C])
[A-C]\s([A-C][A-C])?
[A-C]{2}\d{2}
@|TH[12]
@(@|TH[12])?
@(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))?
@(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))?
(([ECMP]|HA|AK)[SD]|HS)T
[A-CV]{2}
A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr]
(a|b)|(x|y)
(a|b) (x|y)
""".split('\n')for t in tests:
t = t.strip()ifnot t:continueprint'-'*50print t
try:print count(invert(t))for s in invert(t):print s
exceptParseFatalException,pfe:print pfe.msg
printcontinueprintif __name__ =="__main__":
main()
Réponses:
Il s'agit d'une expression régulière récursive et n'est pas prise en charge par de nombreux moteurs d'expression régulière. Ceux basés sur PCRE devraient le supporter.
Sans espace ni commentaires:
.NET ne prend pas directement en charge la récursivité. (Les constructions
(?1)
et(?R)
.) La récursivité devrait être convertie en comptage des groupes équilibrés:Compacté:
D'après les commentaires:
Il validera uniquement la partie regex des substitutions et des traductions.
s/<this part>/.../
C'est possible si le moteur d'expression régulière prend en charge la récursivité, comme PCRE, mais cela ne peut plus vraiment être appelé des expressions régulières.
"En théorie, la théorie et la pratique sont les mêmes. En pratique, elles ne le sont pas." Presque tous ceux qui connaissent les expressions régulières savent que les expressions régulières ne prennent pas en charge la récursivité. Mais PCRE et la plupart des autres implémentations prennent en charge bien plus que les expressions régulières de base.
Ce modèle exploite une extension appelée expressions régulières récursives. Ceci n'est pas pris en charge par la saveur POSIX de l'expression régulière. Vous pouvez essayer avec le commutateur -P, pour activer la saveur regex PCRE.
Cela est vrai pour les expressions régulières classiques. Certaines implémentations modernes autorisent la récursivité, ce qui en fait un langage sans contexte, bien qu'il soit quelque peu verbeux pour cette tâche.
[^?+*{}()[\]\\|]
correspondra à n'importe quel caractère unique, ne faisant partie d'aucune des autres constructions. Cela inclut à la fois littérale (a
-z
), et certains caractères spéciaux (^
,$
,.
).la source
.{,1}
est inégalée. Passez aux^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d*(?:,\d*)?\})[?+]?)?|\|)*)$
correspondances. CHANGER\d+
jusqu'à\d*
[a-b-c]
.Peu probable.
Évaluez-le dans un
try..catch
ou ce que votre langue propose.la source
Non, si vous parlez strictement d'expressions régulières et que vous n'incluez pas certaines implémentations d'expressions régulières qui sont en fait des grammaires sans contexte.
Il existe une limitation des expressions régulières qui rend impossible l'écriture d'une expression régulière qui correspond à toutes et uniquement aux expressions régulières. Vous ne pouvez pas faire correspondre des implémentations telles que des accolades qui sont appariées. Les expressions rationnelles utilisent de nombreuses constructions de ce type, prenons l'
[]
exemple. Chaque fois qu'il y a un,[
il doit y avoir une correspondance]
, ce qui est assez simple pour une expression régulière"\[.*\]"
.Ce qui rend impossible les expressions régulières, c'est qu'elles peuvent être imbriquées. Comment pouvez-vous écrire une expression régulière qui correspond aux crochets imbriqués? La réponse est que vous ne pouvez pas sans une expression régulière infiniment longue. Vous pouvez faire correspondre n'importe quel nombre de parenthèses imbriquées par la force brute, mais vous ne pouvez jamais faire correspondre un ensemble arbitrairement long de crochets imbriqués.
Cette capacité est souvent appelée comptage, car vous comptez la profondeur de l'imbrication. Une expression régulière par définition n'a pas la capacité de compter.
J'ai fini par écrire " Limitations des expressions régulières " à ce sujet.
la source
Bonne question.
Les vraies langues régulières ne peuvent pas décider de parenthèses bien formées profondément imbriquées. Si votre alphabet contient
'('
et')'
le but est de décider si une chaîne de ceux-ci a une parenthèse correspondante bien formée. Comme il s'agit d'une exigence nécessaire pour les expressions régulières, la réponse est non.Cependant, si vous assouplissez l'exigence et ajoutez une récursivité, vous pouvez probablement le faire. La raison en est que la récursivité peut agir comme une pile vous permettant de "compter" la profondeur d'imbrication actuelle en poussant sur cette pile.
Russ Cox a écrit " La correspondance d'expression régulière peut être simple et rapide ", qui est un merveilleux traité sur la mise en œuvre du moteur regex.
la source
Non, si vous utilisez des expressions régulières standard.
La raison en est que vous ne pouvez pas satisfaire le lemme de pompage pour les langues régulières. Les Etats lemme de pompage d' une chaîne appartenant au langage « L » est régulier s'il existe un certain nombre « N » de telle sorte que, après avoir divisé la chaîne en trois sous - chaînes
x
,y
,z
, de sorte que|x|>=1 && |xy|<=N
, vous pouvez répétery
autant de fois que vous voulez et le la chaîne entière appartiendra toujoursL
.Une conséquence du lemme de pompage est que vous ne pouvez pas avoir de chaînes régulières sous la forme
a^Nb^Mc^N
, c'est-à-dire deux sous-chaînes ayant la même longueur séparées par une autre chaîne. De toute façon, vous divisez ces chaînes enx
,y
etz
, vous ne pouvez pas "pomper"y
sans obtenir une chaîne avec un nombre différent de "a" et "c", laissant ainsi la langue d'origine. C'est le cas, par exemple, avec des parenthèses dans les expressions régulières.la source
Bien qu'il soit parfaitement possible d'utiliser une expression rationnelle récursive comme l'a signalé MizardX, pour ce genre de choses, il est beaucoup plus utile d'un analyseur. Les expressions rationnelles étaient à l'origine destinées à être utilisées avec des langages réguliers, étant récursives ou ayant des groupes d'équilibrage n'est qu'un patch.
Le langage qui définit les expressions rationnelles valides est en fait une grammaire sans contexte, et vous devez utiliser un analyseur approprié pour le gérer. Voici un exemple de projet universitaire d'analyse syntaxique des expressions rationnelles simples (sans la plupart des constructions). Il utilise JavaCC. Et oui, les commentaires sont en espagnol, bien que les noms de méthode soient assez explicites.
la source
Vous pouvez soumettre l'expression rationnelle à
preg_match
laquelle retournera false si l'expression rationnelle n'est pas valide. N'oubliez pas d'utiliser le@
pour supprimer les messages d'erreur://
.la source
L'exemple suivant de Paul McGuire, originaire du wiki Pyparsing, mais désormais disponible uniquement via la Wayback Machine , donne une grammaire pour analyser certaines expressions rationnelles, dans le but de renvoyer l'ensemble de chaînes correspondantes. En tant que tel, il rejette ceux qui incluent des termes de répétition illimités, comme «+» et «*». Mais cela devrait vous donner une idée de la façon de structurer un analyseur qui traiterait les re.
la source