2010-09-24 12 views
7

Im Geiste der polygenelubricants 'Bemühungen, dumme Dinge mit regulären Ausdrücken zu tun, Ich versuche derzeit, die .NET Regex-Engine für mich zu multiplizieren.Multiplikation mit .NET regulären Ausdrücken

Dies hat natürlich keinen praktischen Wert und ist als eine rein theoretische Übung gemeint.

Bis jetzt bin ich bei diesem Monster angekommen, das überprüfen sollte, ob die Anzahl von 1s multipliziert mit der Anzahl von 2s gleich der Anzahl von 3s in der Zeichenfolge ist.

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

Leider funktioniert es nicht, und ich bin ratlos warum. Ich habe es kommentiert, um Ihnen zu zeigen, was ich denke, dass der Motor tun sollte, aber ich kann hier weg sein. Beispiele für Ausgabe:

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

Jeder Gedanke sind willkommen!

Antwort

1

Ich bin mir ziemlich sicher, dass das Problem in dieser Linie ist:

(?<b-c>)* 

Von dem, was ich sagen kann, ohne Text dort übereinstimmen, lehnt die Regex es passen mehr als einmal. ich abgespeckt die Regex auf die folgenden:

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

die auf 1 geht aber nicht auf 111. Auch versucht (?<-a>)*. Kein Unterschied. Allerdings geht es zu

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

Wechsel sowohl auf 12 und 111222. Wenn Sie also von einer Übereinstimmung von "" zu einer Übereinstimmung mit etwas wechseln, funktioniert die Regex wie erwartet.

Zurück zu Ihrer ursprünglichen Regex, meine Schätzung ist, dass (?<b-c>)* nur 0-1 mal entspricht, was erklärt, warum eine 2 in Ihrer Zeichenfolge funktioniert, aber mehr als eine hat fehlgeschlagen.

eine Reihe von 11 fehl auch, die die gleichen Logik folgt, wie das gesamte Spiel macht "", die höchstwahrscheinlich bedeutet, dass es nur ein einziges Mal übereinstimmt, was (?(a)(?!)) zum Scheitern verurteilt.

+0

Schöne Analyse, danke! Ich werde sehen, ob ich das beheben kann ... =) – Jens

0

Mit Joels Input konnte ich es zum Laufen bringen, indem ich den Algorithmus geringfügig änderte, um diese Zeilen zu vermeiden.

Siehe:

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

Ich möchte ein ideone Link geben, aber das Ergebnis, das ich es unterscheidet sich von Mine zu bekommen. Vielleicht, weil ich .NET 4.0 verwende und sie nicht?

+0

Das scheitert noch immer an dem '11'-Fall, aber ich habe keinen weiteren Fehlerfall dafür gefunden. –