2008-10-05 13 views

Répondre

597
/ 
^            # 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 regex récursive qui n'est pas prise en charge par de nombreux moteurs regex. Les PCRE basés devraient le soutenir.

Sans espaces et des commentaires:

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

.NET ne prend pas en charge directement récursivité. (. Les constructions (?1) et (?R)) La récursion devrait être converti en comptant 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. 

compactés:

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

Vous votant sur la présomption que cela fonctionne réellement. Comme je n'ai bu que deux tasses de café aujourd'hui, je ne suis pas en mesure de le vérifier. –

+0

Est-ce que cela validera les substitutions et les traductions? – slashmais

+0

Il validera seulement la partie regex des substituants et traductions. s/ /.../ –

205

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

+127

Ce n'est pas très entreprenant de votre part. – MusiGenesis

+103

Je pense que c'est une bien meilleure solution que de tenter de le valider via une regex .... –

+12

C'est facile en PHP par exemple: $ valid = (@preg_match ($ regex, '')! == FALSE); – ColinM

35

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 de 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 traité merveilleux sur la mise en œuvre du moteur regex: Regular Expression Matching Can Be Simple And Fast

+2

Merci pour le lien sur l'article Russ Cox – njsf

+0

Cet article suppose que vous n'avez pas besoin de toutes les extensions que les moteurs d'expressions rationnelles typiques fournissent. Un article de suivi traite de l'extraction des submatchs mais il y en a beaucoup plus. – reinierpost

133

Non si vous parlez strictement sur les expressions régulières et ne comprenant pas certaines implémentations d'expressions régulières qui sont en fait libres de contexte grammaires.

Il existe une limitation des expressions régulières qui rend impossible l'écriture d'une regex qui correspond à toutes les regexes. 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 regex impossibles, c'est qu'ils peuvent être imbriqués. 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 fonctionnalité est souvent appelée comptage (vous comptez la profondeur de l'imbrication). Une regex par définition n'a pas la capacité de compter.

EDIT: a fini par écrire un billet de blog à ce sujet: Regular Expression Limitations

+1

Je dois souvent faire la différence entre l'outil de correspondance de texte commun appelé regex et l'expression régulière sur laquelle il était basé. Malheureusement, beaucoup ne voient pas la distinction. RE2 est unique en ce sens qu'il permet seulement l'extension qui peut être traduite en RE simple. Il a également tous les avantages de RE (mémoire limitée, runtime, vitesse), avec la plupart des extensions de syntaxe. –

+0

Pourquoi regex ne trouve pas de paires de crochets? J'ai écrit un analyseur de ma propre langue et il peut vérifier si chaque parenthèse a la fin correspondante. Check it out: https://regex101.com/r/y4xhYo/1 – Soaku

+0

triste la réponse acceptée a 3x plus de votes que celui-ci .. –

5

Bien qu'il soit parfaitement possible d'utiliser une expression régulière récursif comme MizardX a affiché, 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 expressions régulières 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; } 
} 
+4

Être un peu plus agréable, je suis d'accord que vous devriez coller à une langue. Et, sans sembler pro-anglais ou "votre langue craint", Linus Torvalds suggère au moins déjà une norme. –

+17

Je suis d'accord que l'utilisation de l'espagnol, de l'anglais et du spanglish dans le même code n'est pas une bonne pratique. Le problème est que je suis habitué à coder en anglais, mais il y avait quelques directives à suivre (comme commenter en espagnol, ou utiliser certains noms pour les jetons) dans le projet. Quoi qu'il en soit, le but était simplement de donner une idée sur l'algorithme, pas de donner un code de référence complet. –

+0

La plupart de ces mots sont extrêmement similaires dans les deux langues, de toute façon, donc je pense que si vous n'êtes pas totalement dense, il devrait être facile à suivre. – Casey

4

Ce example sur le wiki pyparsing donne une grammaire pour l'analyse syntaxique quelques regexes, aux fins de retourner l'ensemble des chaînes correspondant. 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.

5

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, ''); 
  • renverra 1 si l'expression rationnelle est « // ».
  • retournera 0 si la regex est correcte.
  • retournera faux sinon.
0

Essayez celui-ci ...

//regular expression for email 
    var pattern = /^(([^<>()[\]\\.,;:\[email protected]\"]+(\.[^<>()[\]\\.,;:\[email protected]\"]+)*)|(\".+\"))@((\[[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; 
    } 
+2

Alors que ce code peut répondre à la question, fournissant un contexte supplémentaire concernant pourquoi et/ou comment ce code répond à la question améliore sa valeur à long terme. – rollstuhlfahrer