Question Existe-t-il une expression régulière pour détecter une expression régulière valide?


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.


617
2017-10-05 17:07


origine


Réponses:


/
^                                             # 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
/

C'est une regex récursive, et n'est pas supporté par beaucoup de moteurs regex. Les PCRE basés devraient le soutenir.

Sans espaces et commentaires:

/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/

.NET ne prend pas en charge la récursivité directement. (Le (?1) et (?R) construit). La récursion devrait être convertie en un comptage de 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.

Compacté:

^(?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>|\?<[^\W\d]\w*>|\?'[^\W\d]\w*')?(?<N>)|\)(?<-N>))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*$(?(N)(?!))

624
2017-10-05 17:15



Improbable.

Évaluer dans un try..catch ou tout ce que votre langue fournit.


217
2017-10-05 17:14



Non si vous parlez strictement des expressions régulières et n'incluez pas certaines implémentations d'expressions régulières qui sont en fait des grammaires sans contexte.

Il y a une limitation des expressions régulières qui rend impossible l'écriture d'une regex qui correspond à tous et seulement aux regex. Vous ne pouvez pas faire correspondre les implémentations telles que les accolades qui sont jumelées. Les expressions rationnelles utilisent beaucoup de ces constructions, prenons [] comme exemple. Chaque fois qu'il y a un [il doit y avoir une correspondance]. Assez simple pour une regex "[. *]".

Ce qui rend les expressions régulières impossibles, c'est qu'elles peuvent être imbriquées. Comment pouvez-vous écrire une regex qui correspond aux parenthèses imbriquées? La réponse est que vous ne pouvez pas sans une regex infiniment longue. Vous pouvez faire correspondre n'importe quel nombre de parens imbriqués par force brute, mais vous ne pouvez jamais correspondre à un ensemble arbitrairement long de parenthèses imbriquées.

Cette capacité est souvent appelée comptage (vous comptez la profondeur de l'imbrication). Une regex par définition n'a pas la capacité de compter.

MODIFIER: J'ai fini par écrire un article sur ce sujet: Limitations d'expression régulière


147
2017-10-05 18:02



Bonne question. Les vrais langages réguliers ne peuvent pas décider arbitrairement des parenthèses bien formées et imbriquées. Par exemple, si votre alphabet contient '(' et ')', l'objectif est de décider si une chaîne de caractères a une parenthèse correspondante. Puisque c'est une exigence nécessaire pour les expressions régulières, la réponse est non.

Cependant: si vous desserrez l'exigence et ajoutez la 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 un merveilleux traité sur la mise en œuvre du moteur regex: L'expression régulière correspondant peut être simple et rapide


36
2017-10-05 17:38



Bien qu'il soit parfaitement possible d'utiliser une regex récursive comme MizardX a posté, pour ce genre de choses, il est beaucoup plus utile un analyseur. Les expressions rationnelles étaient à l'origine destinées à être utilisées avec des langages réguliers, être récursives ou avoir des groupes d'équilibrage n'est qu'un patch.

Le langage qui définit les regexes valides est en fait une grammaire sans contexte, et vous devez utiliser un analyseur approprié pour le manipuler. Voici un exemple pour un projet universitaire d'analyse d'expressions rationnelles simples (sans la plupart des constructions). Il utilise JavaCC. Et oui, les commentaires sont en espagnol, bien que les noms de méthodes soient assez explicites.

SKIP :
{
    " "
|   "\r"
|   "\t"
|   "\n"
}
TOKEN : 
{
    < DIGITO: ["0" - "9"] >
|   < MAYUSCULA: ["A" - "Z"] >
|   < MINUSCULA: ["a" - "z"] >
|   < LAMBDA: "LAMBDA" >
|   < VACIO: "VACIO" >
}

IRegularExpression Expression() :
{
    IRegularExpression r; 
}
{
    r=Alternation() { return r; }
}

// Matchea disyunciones: ER | ER
IRegularExpression Alternation() :
{
    IRegularExpression r1 = null, r2 = null; 
}
{
    r1=Concatenation() ( "|" r2=Alternation() )?
    { 
        if (r2 == null) {
            return r1;
        } else {
            return createAlternation(r1,r2);
        } 
    }
}

// Matchea concatenaciones: ER.ER
IRegularExpression Concatenation() :
{
    IRegularExpression r1 = null, r2 = null; 
}
{
    r1=Repetition() ( "." r2=Repetition() { r1 = createConcatenation(r1,r2); } )*
    { return r1; }
}

// Matchea repeticiones: ER*
IRegularExpression Repetition() :
{
    IRegularExpression r; 
}
{
    r=Atom() ( "*" { r = createRepetition(r); } )*
    { return r; }
}

// Matchea regex atomicas: (ER), Terminal, Vacio, Lambda
IRegularExpression Atom() :
{
    String t;
    IRegularExpression r;
}
{
    ( "(" r=Expression() ")" {return r;}) 
    | t=Terminal() { return createTerminal(t); }
    | <LAMBDA> { return createLambda(); }
    | <VACIO> { return createEmpty(); }
}

// Matchea un terminal (digito o minuscula) y devuelve su valor
String Terminal() :
{
    Token t;
}
{
    ( t=<DIGITO> | t=<MINUSCULA> ) { return t.image; }
}

7
2017-10-06 14:15



Vous pouvez soumettre la regex à preg_match qui retournera false si la regex n'est pas valide. Ne pas oublier d'utiliser le '@' pour supprimer les messages d'erreur:

@preg_match($regexToTest, '');
  • retournera 1 si la regex est '//'.
  • retournera 0 si la regex est correcte.
  • retournera faux sinon.

5
2017-08-28 18:09



Ce Exemple sur le wiki pyparsing donne une grammaire pour l'analyse certains regexes, dans le but de renvoyer l'ensemble des chaînes correspondantes. En tant que tel, il rejette ces re qui comprennent des termes de répétition illimités, comme «+» et «*». Mais cela devrait vous donner une idée sur la façon de structurer un analyseur qui traiterait les re.


4
2018-05-25 12:51



Essaye celui-là...

//regular expression for email
    var pattern = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    if(pattern.test(email)){
        return true;
    } else {
        return false;
    }

-3
2018-03-05 05:52