2012-05-09 6 views
6

L'espressione è:Come posso trasformare questa espressione di Backus-Naur Form in un Regex (.Net)?

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

Senso descrittore "N" o uno o più dei descrittori elencati senza ripetizione.

Il migliore che ho ottenuto è:

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

Ma ciò non impedisce la ripetizione.

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

che impedisce ripetizione ma poi richiede un ordine specifico per gli elementi, che non è realmente OK o.

Qualche idea?

(non sono realmente sicuro che l'espressione BNF in sé non consente la ripetizione, ma questo è quello che mi serve.)

+0

http://kore-nordmann.de/blog/do_NOT_parse_using_regexp.html Usa le espressioni regolari per riconoscere parole, non strutture. –

+0

Immagino che abbia senso. Ma cosa dovrei usare per riconoscere questa struttura? @DavidBrabant Verrà utilizzato per convalidare l'input del modulo indicato. – Daniel

+0

Oppure PCRE è il metodo che stai suggerendo? – Daniel

risposta

4

Bene, è possibile, ma non è abbastanza:

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); 

Questa soluzione utilizza negative lookahead assertions.

+0

Bello, grazie! – Daniel

+0

Solo una domanda @Tim. Che funzione ha il '?:'? Sembra che funzioni senza quei due. – Daniel

+0

@Daniel: L'unica differenza è che '(...)' è un * catturando * gruppo, il che significa che il motore regex memorizza ciò che è stato abbinato all'interno di quel gruppo in un backreference a cui è possibile riferirsi successivamente. Se non hai bisogno di farlo, '(?: ...)' funziona allo stesso modo, ma senza memorizzare quella parte della partita. Pertanto, sono un po 'più efficienti. –

1

io non sono sicuro che sia possibile anche per un .net Regex (che è più potente della definizione più rigorosa di "lingua normale") per fare ciò; e in ogni caso, se non avete l'obbligo di utilizzare solo un Regex, non c'è nulla di male (a mio avviso) 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; 
} 

E 'il codice più breve che risolve il problema? No. È leggibile e mantenibile? Penso che sia così.

(si potrebbe scrivere un metodo di utilità con la firma int MaxN(params int[] numbers) se si voleva)

Problemi correlati