Regex validating regex [fermé]

17

Construisez une expression régulière qui acceptera une chaîne d'expression régulière comme entrée et vérifiez si elle est valide. Fondamentalement, votre expression régulière devrait pouvoir se valider. (Tout regex invalide ne doit pas être validé, vous ne pouvez donc pas l'utiliser .*.;))

Votre saveur doit être entièrement prise en charge par des implémentations bien connues (Perl, sed, grep, gawk, etc.), et elle doit pleinement prendre en charge ce que ces implémentations prennent en charge. [Ne vous inquiétez pas pour l'avocat qui parle; J'essaie simplement de supprimer toutes les lacunes possibles pour les intelligentes ***.]


Je ferais un , mais je suis inquiet que ça va donner un avantage à ceux qui connaissent et utilisent les saveurs non-riches en fonctionnalités. Ou mes inquiétudes sont-elles infondées?

Mateen Ulhaq
la source
8
pas possible, les crochets imbriqués arbitraires font d'une regex une grammaire sans contexte, (le remplacer par une notation polonaise a également besoin d'une pile)
ratchet freak
@ratchet Augh, vous avez peut-être raison.
Mateen Ulhaq
1
il existe des extensions sur les langues régulières qui peuvent permettre de faire correspondre les crochets, mais je ne sais pas comment le faire
ratchet freak
8
C'est forcément possible avec les expressions rationnelles de Perl.
Peter Taylor
1
Les expressions régulières @BrianVandenberg implémentées dans les langues modernes sont à peu près toutes non régulières ... dès que vous ajoutez des références arrières, vous pouvez faire correspondre des langues non régulières. De plus, Perl / PCRE et .NET sont suffisamment puissants pour correspondre à l'imbrication correcte.
Martin Ender

Réponses:

22

Rubis

J'ai essayé de faire correspondre autant que possible la syntaxe réelle de l'arôme regex de Ruby, mais il y a quelques bizarreries: il accepte quelques lookbhinds qui sont en fait invalides (comme (?<=(?<!))), et il reconnaît les plages de caractères vides comme D-A. Ce dernier pourrait être corrigé pour ASCII, mais l'expression régulière est suffisamment longue.

\A(?<main>
    (?!
        \{(\d+)?,(\d+)?\} # do not match lone counted repetition
    )
    (?:
        [^()\[\]\\*+?|<'] | # anything but metacharacters
        (?<cclass>
            \[ \^? (?: # character class
                (?: # character class
                    [^\[\]\\-] | # anything but square brackets,  backslashes or dashes
                    \g<esc> |
                    \[ : \^? (?: # POSIX char-class
                        alnum | alpha | word | blank | cntrl | x?digit | graph | lower | print | punct | space | upper
                    ) : \] |
                    - (?!
                        \\[dwhsDWHS]
                    ) # range / dash not succeeded by a character class
                )+ |
                \g<cclass> # more than one bracket as delimiter
            ) \]
        ) |
        (?<esc>
            \\[^cuxkg] | # any escaped character
            \\x \h\h? | # hex escape
            \\u \h{4} | # Unicode escape
            \\c . # control escape
        ) |
        \\[kg] (?:
            < \w[^>]* (?: > | \Z) |
            ' \w[^']* (?: ' | \Z)
        )? | # named backrefs
        (?<! (?<! \\) \\[kg]) [<'] | # don't match < or ' if preceded by \k or \g
        \| (?! \g<rep> ) | # alternation
        \( (?: # group
            (?:
                \?
                (?:
                    [>:=!] | # atomic / non-capturing / lookahead
                    (?<namedg>
                        < [_a-zA-Z][^>]* > |
                        ' [_a-zA-Z][^']* ' # named group
                    ) |
                    [xmi-]+: # regex options
                )
            )?
            \g<main>*
        ) \) |
        \(\?<[!=] (?<lbpat>
            (?! \{(\d+)?,(\d+)?\} )
            [^()\[\]\\*+?] |
            \g<esc>  (?<! \\[zZ]) |
            \g<cclass> |
            \( (?: # group
                (?:
                    \?: |
                    \? \g<namedg> |
                    \? <[!=]
                )?
                \g<lbpat>*
            ) \) |
            \(\?\# [^)]* \)
        )* \)
        |
        \(\? [xmi-]+ \) # option group
        (?! \g<rep> ) 
        |
        \(\?\# [^)]*+ \) # comment
        (?! \g<rep> )
    )+
    (?<rep>
        (?:
            [*+?] | # repetition
            \{(\d+)?,(\d+)?\} # counted repetition
        )
        [+?]? # with a possessive/lazy modifier
    )?
)*\Z

Version illisible:

\A(?<main>(?!\{(\d+)?,(\d+)?\})(?:[^()\[\]\\*+?|<']|(?<cclass>\[\^?(?:(?:[^\[\]\\-]|\g<esc>|\[:\^?(?:alnum|alpha|word|blank|cntrl|x?digit|graph|lower|print|punct|space|upper):\]|-(?!\\[dwhsDWHS]))+|\g<cclass>)\])|(?<esc>\\[^cuxkg]|\\x\h\h?|\\u\h{4}|\\c.)|\\[kg](?:<\w[^>]*(?:>|\Z)|'\w[^']*(?:'|\Z))?|(?<!(?<!\\)\\[kg])[<']|\|(?!\g<rep>)|\((?:(?:\?(?:[>:=!]|(?<namedg><[_a-zA-Z][^>]*>|'[_a-zA-Z][^']*')|[xmi-]+:))?\g<main>*)\)|\(\?<[!=](?<lbpat>(?!\{(\d+)?,(\d+)?\})[^()\[\]\\*+?]|\g<esc>(?<!\\[zZ])|\g<cclass>|\((?:(?:\?:|\?\g<namedg>|\?<[!=])?\g<lbpat>*)\)|\(\?#[^)]*\))*\)|\(\?[xmi-]+\)(?!\g<rep>)|\(\?#[^)]*+\)(?!\g<rep>))+(?<rep>(?:[*+?]|\{(\d+)?,(\d+)?\})[+?]?)?)*\Z
Lowjacker
la source
28
Ne sont-ils pas tous les deux la version illisible?
Kibbee
2
@Kibbee Le premier est raisonnablement lisible si vous connaissez bien l'expression régulière.
Lowjacker
1
Comment cela garantit-il qu'il n'y a pas de références numériques invalides?
Martin Ender
1
Je suppose que non. Là encore, ce n'est pas la seule limitation qu'il a (voir ci-dessus). Certaines choses pourraient être corrigées, mais l'expression régulière deviendrait ridiculement longue.
Lowjacker