2012-05-09 8 views
6

La expresión es:¿Cómo puedo transformar esta expresión de Backus-Naur Form en Regex (.Net)?

N | (1 { A | B | C | D | E1 | E2 | E3 }) 

Significado el descriptor "N" o uno o más de los descriptores que figuran sin repetición.

El mejor que he conseguido es:

@"^(N|(A|B|C|D|E1|E2|E3){1,})$" 

Pero eso no impide la repetición.

@"^(N|(A{0,1}B{0,1}...)$" 

que evita la repetición, pero luego requiere un orden específico para los elementos, que no es muy bien tampoco.

¿Alguna idea?

(no estoy realmente seguro de que la propia expresión BnF no permite la repetición, pero eso es lo que necesito.)

+0

http://kore-nordmann.de/blog/do_NOT_parse_using_regexp.html Usa expresiones regulares para reconocer palabras, no estructuras. –

+0

Supongo que tiene sentido. Pero, ¿qué usaría para reconocer esta estructura? @DavidBrabant Se usará para validar la entrada del formulario mencionado. – Daniel

+0

¿O es PCRE el método que está sugiriendo? – Daniel

Respuesta

4

Bueno, se puede, pero no es bastante:

Regex regexObj = new Regex(
    @"^   # Start of string 
    (?:   # Either match... 
    N   # N 
    |    # or... 
    (?:   # Match one of the following: 
     A(?!.*A) # A unless followed somewhere later by another A 
    |   # or 
     B(?!.*B) # B unless... 
    |   # etc. etc. 
     C(?!.*C) 
    | 
     D(?!.*D) 
    | 
     E1(?!.*E1) 
    | 
     E2(?!.*E2) 
    | 
     E3(?!.*E3) 
    )+   # one or more times 
    )    # End of alternation 
    $    # End of string", 
    RegexOptions.IgnorePatternWhitespace); 

Esta solución utiliza negative lookahead assertions.

+0

¡Agradable, gracias! – Daniel

+0

Solo una pregunta @Tim. ¿Qué función tiene el '?:' Tener? Parece estar funcionando sin esos dos. – Daniel

+0

@Daniel: La única diferencia es que '(...)' es un grupo * de captura *, lo que significa que el motor de expresiones regulares almacena lo que estaba emparejado dentro de ese grupo en una referencia posterior que luego puede consultar. Si no necesita hacer eso, '(?: ...)' funciona igual, pero sin almacenar esa parte del partido. Por lo tanto, son un poco más eficientes. –

1

no estoy seguro de que es posible incluso para un .net Regex (que es más poderoso que el la definición más estricta de "lenguaje regular") para hacer esto; y de todos modos, a menos que tenga un requisito de utilizar sólo un Regex, no hay nada malo (a la mente) con:

bool IsValid(string input) 
{ 
    var Ns = input.Count(c => c == 'N'); 
    var As = input.Count(c => c == 'A'); 
    // etc 
    var E1s = Regex.Matches(input, "E1").Count 
    // etc 

    var maxDescriptorCount = (new[] { As, ... ,E1s, ... }).Max(); 

    var isValid = 
     ((Ns == 1) && (maxDescriptorCount == 0)) 
     || 
     ((Ns == 0) && (maxDescriptorCount == 1)) 
     ; 

    return isValid; 
} 

¿Es el código más corto que resuelve el problema? No. ¿Es legible y mantenible? Creo que si.

(Se puede escribir un método de utilidad con la firma int MaxN(params int[] numbers) si quería)

Cuestiones relacionadas