2010-09-24 8 views
7

Nello spirito di polygenelubricants 'sforzi per fare cose stupide con espressioni regolari, Attualmente sto cercando di ottenere il motore regex .NET da moltiplicare per me.Moltiplicazione con espressioni regolari .NET

Questo ha, naturalmente, nessun valore pratico ed è inteso come un esercizio puramente teorico.

Finora, sono arrivato a questo mostro, che dovrebbe controllare se il numero di 1s moltiplicato per il numero di 2 è uguale al numero di 3 nella stringa.

Regex regex = new Regex(
@" 
^ 
(1(?<a>))* # increment a for each 1 
(2(?<b>))* # increment b for each 2 
    (?(a) # if a > 0 
     (     
      (?<-a>)    # decrement a 
      (3(?<c-b>))*  # match 3's, decrementing b and incrementing c until 
           # there are no 3's left or b is zero 
      (?(b)(?!))   # if b != 0, fail 
      (?<b-c>)*   # b = c, c = 0 
     ) 
    )*  # repeat 
(?(a)(?!)) # if a != 0, fail 
(?(c)(?!)) # if c != 0, fail 
$ 
", RegexOptions.IgnorePatternWhitespace); 

Sfortunatamente, non funziona, e non riesco a capire perché. L'ho commentato per mostrarti cosa penso che dovrebbe fare il motore, ma potrei essere qui. Esempi di uscita:

regex.IsMatch("123") // true, correct 
regex.IsMatch("22") // true, correct 
regex.IsMatch("12233") // false, incorrect 
regex.IsMatch("11233"); // true, correct 

ogni pensiero sono i benvenuti!

risposta

1

Sono piuttosto sicuro che il problema è in questa linea:

(?<b-c>)* 

Da quello che posso dire, senza testo per abbinare in là, il Regex rifiuta di corrispondere più di una volta. Mi snellita la Regex al seguente:

(1(?<a>))* 
(?(a)(?<-a>))* 
(?(a)(?!)) 

che trasmette 1 ma non riesce a 111. Ha anche provato (?<-a>)*. Nessuna differenza. Tuttavia, cambiandolo

(1(?<a>))* 
(?(a)((?<-a>)(2(?<b>))(?<-b>)))* 
(?(a)(?!)) 

passa sia 12 e 111222. Quindi passare da una partita di "" a una partita con qualcosa fa sì che il Regex funzioni come previsto.

Tornando al tuo Regex originale, la mia ipotesi è che (?<b-c>)* corrisponda solo a 0-1 volte, il che spiega perché avere un 2 nella tua stringa funziona, ma avere più di uno fallisce.

utilizzo di una stringa di 11 riesce inoltre, che segue la stessa logica, come che rende l'intera partita "", che molto probabilmente significa che corrisponde solo una volta, causando (?(a)(?!)) al sicuro.

+0

Bella analisi, grazie! Vedrò se posso aggiustarlo ... =) – Jens

0

Con l'input di Joel sono riuscito a farlo funzionare, modificando leggermente l'algoritmo per evitare quelle linee (?<b-c>)*.

Ecco:

Regex regex = new Regex(
@" 
^ 
(1(?<a>))* # increment a for each 1 
(2(?<b>))* # increment b for each 2 
    (?(a) # if a > 0 
     (
      (?<-a>)    # decrement a 
      (?(b)    # if b > 0 
       (          
        (3(?<c-b>))*  # match 3's, decrementing b and incrementing c until 
             # there are no 3's left or b is zero 
        (?(b)(?!))   # if b != 0, fail 
       ) 
       |      # else (b = 0) 
       (
        (3(?<b-c>))*  # match 3's, decrementing c and incrementing b until 
             # there are no 3's left or c is zero 
        (?(c)(?!))   # if c != 0, fail 
       ) 
      ) 
     ) 
    )*  # repeat 
(?(a)(?!)) # if a != 0, fail 
$ 
", RegexOptions.IgnorePatternWhitespace); 

Mi piacerebbe dare un collegamento Ideone, ma il risultato non arrivo diverso dal mio. Forse perché sto usando .NET 4.0 e loro no?

+0

Questo fallisce ancora nel caso '11', ma non ho trovato un altro caso di errore per questo. –