2008-10-05 26 views

Respuesta

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 
/

Esta es una expresión regular recursiva, y no es compatible con muchos motores de expresiones regulares. Los basados ​​en PCRE deberían ser compatibles.

Sin espacios en blanco y comentarios:

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

.NET no admite recursión directa. (. Los (?1) y (?R) construcciones) La recursión tendría que ser convertido en grupos equilibrados de conteo:

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

compactado:

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

Votando en la presunción de que esto realmente funciona. Como solo he tomado dos tazas de café hoy, no estoy a la altura de verificarlo. –

+0

¿Esto validará las sustituciones y las traducciones? – slashmais

+0

Validará solo la parte de expresión regular de los substitutinos y las traducciones. s/ /.../ –

205

Improbable.

Evalúelo en un try..catch o cualquiera que sea su idioma.

+127

Eso no es muy productivo para usted. – MusiGenesis

+103

Creo que esta es una solución mucho mejor que intentar validarla a través de una expresión regular ... –

+12

Esto es fácil en PHP, por ejemplo: $ valid = (@preg_match ($ regex, '')! == FALSE); – ColinM

35

Buena pregunta. Los verdaderos lenguajes regulares no pueden decidir paréntesis bien formados anidados de manera arbitraria. Es decir, si su alfabeto contiene '(' y ')', el objetivo es decidir si una cadena de estos tiene paréntesis coincidentes bien formados. Como este es un requisito necesario para las expresiones regulares, la respuesta es no.

Sin embargo, si afloja el requisito y agrega recursión, probablemente pueda hacerlo. La razón es que la recursión puede actuar como una 'pila' que le permite 'contar' la profundidad de anidación actual presionando sobre esta pila.

Russ Cox ha escrito un tratado de maravilla en expresiones regulares implementación del motor: Regular Expression Matching Can Be Simple And Fast

+2

Gracias por el enlace en el artículo de Russ Cox – njsf

+0

Ese artículo asume que no necesita todas las extensiones que proporcionan los motores de expresiones regulares. Un artículo de seguimiento analiza la extracción de subcampamentos, pero hay mucho más. – reinierpost

133

No se si está estrictamente hablando acerca de las expresiones regulares y no incluyendo algunas implementaciones de expresiones regulares que son realmente gramática libre de contexto.

Hay una limitación de las expresiones regulares que hace que sea imposible escribir una expresión regular que coincida con todas y solo las expresiones regulares. No puede hacer coincidir implementaciones tales como llaves que están emparejadas. Regexes usa muchos de estos constructos, permite tomar [] como ejemplo. Siempre que haya un [debe haber una coincidencia]. Lo suficientemente simple para una expresión regular "[. *]".

Lo que hace imposible que las expresiones regulares sean anidadas. ¿Cómo se puede escribir una expresión regular que coincida con los paréntesis anidados? La respuesta es que no se puede sin una expresión regular infinitamente larga. Puede hacer coincidir cualquier número de parens anidados a través de la fuerza bruta, pero nunca puede coincidir con un conjunto arbitrariamente largo de paréntesis anidados.

Esta capacidad a menudo se conoce como conteo (se está contando la profundidad de la anidación). Una expresión regular por definición no tiene la capacidad de contar.

EDIT: terminó escribiendo un blog acerca de esto: Regular Expression Limitations

+1

A menudo tengo que diferenciar entre la herramienta de coincidencia de texto común llamada expresión regular y expresión regular en la que se basa. Lamentablemente, muchos no ven la distinción. RE2 es único ya que solo permite la extensión que se puede traducir de nuevo a RE simple. También tiene todas las ventajas de RE (memoria limitada, tiempo de ejecución, velocidad), con la mayoría de las extensiones de sintaxis. –

+0

¿Por qué regex no puede encontrar pares de corchetes? Escribí un analizador de mi propio idioma y puedo verificar si cada corchete tiene un final coincidente. Compruébelo: https://regex101.com/r/y4xhYo/1 – Soaku

+0

lamentablemente la respuesta aceptada tiene 3x más votos que esta .. –

5

Aunque es perfectamente posible utilizar una expresión regular recursiva como MizardX ha publicado, para este tipo de cosas es mucho más útil un programa de análisis. Regexes originalmente fue pensado para ser usado con los lenguajes regulares, recursivo o tener grupos de equilibrio es solo un parche.

El lenguaje que define expresiones regulares válidas es en realidad una gramática libre de contexto, y debe usar un analizador apropiado para manejarlo. Aquí hay un ejemplo de un proyecto universitario para analizar expresiones regulares simples (sin la mayoría de los constructos). Utiliza JavaCC. Y sí, los comentarios están en español, aunque los nombres de los métodos son bastante fáciles de entender.

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

Siendo un poco mejor, estoy de acuerdo en que debes apegarte a un idioma. Y, sin sonar pro-inglés o "su idioma apesta", Linus Torvalds al menos ya sugiere un estándar. –

+17

Acepto que usar español, inglés y spanglish en el mismo código no es una práctica feliz. El problema es que estoy acostumbrado a codificar en inglés, pero había algunas pautas a seguir (como comentar en español o usar ciertos nombres para tokens) en el proyecto. De todos modos, el punto era solo dar una idea sobre el algoritmo, no dar un código de referencia completo. –

+0

La mayoría de estas palabras son extremadamente similares en ambos idiomas, de todos modos, por lo que creo que si no es totalmente denso, debería ser fácil de seguir. – Casey

4

Este example en el wiki pyparsing da una gramática para analizar algunas expresiones regulares, a los efectos de devolver el conjunto de cadenas que coinciden. Como tal, rechaza aquellas referencias que incluyen términos de repetición ilimitada, como '+' y '*'. Pero debería darle una idea sobre cómo estructurar un analizador que pueda procesar re.

5

Puede enviar la expresión regular a preg_match, que devolverá falso si la expresión regular no es válida. No se olvide de utilizar la '@' para suprimir mensajes de error:

@preg_match($regexToTest, ''); 
  • volverá 1 si la expresión regular es '//'.
  • devolverá 0 si la expresión regular está bien.
  • devolverá falso de lo contrario.
0

Prueba con esto ...

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

Si bien este código puede responder a la pregunta, proporcionar un contexto adicional con respecto a por qué y/o cómo este código responde la pregunta mejora su valor a largo plazo. – rollstuhlfahrer

Cuestiones relacionadas