2010-09-24 5 views
7

Dans l'esprit de polygenelubricants 'efforts pour faire des choses idiotes avec des expressions régulières, J'essaye actuellement de faire multiplier le moteur .ge regex pour moi.Multiplication avec des expressions régulières .NET

Ceci n'a bien sûr aucune valeur pratique et se veut un exercice purement théorique. Jusqu'à présent, je suis arrivé à ce monstre, qui devrait vérifier si le nombre de 1 multiplié par le nombre de 2 est égal au nombre de 3 dans la chaîne.

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

Malheureusement, cela ne fonctionne pas, et je ne sais pas pourquoi. Je l'ai commenté pour vous montrer ce que je pense que le moteur devrait faire, mais je suis peut-être ici. Exemples de sortie:

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

Toute pensée sont les bienvenus!

Répondre

1

Je suis sûr que le problème est dans cette ligne:

(?<b-c>)* 

D'après ce que je peux dire, sans texte pour correspondre là, le Regex refuse de faire correspondre plus d'une fois. Je maigri la Regex à ce qui suit:

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

qui passe sur 1 mais échoue sur 111. Également essayé (?<-a>)*. Aucune différence. Toutefois, la modification à

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

passe sur les deux 12 et 111222. Donc, passer d'une correspondance de "" à une correspondance avec quelque chose entraîne le fonctionnement normal de Regex.

Pour en revenir à votre Regex d'origine, je suppose que (?<b-c>)* correspond seulement 0-1 fois, ce qui explique pourquoi avoir un 2 dans votre chaîne fonctionne, mais en ayant plus d'un échoue.

En utilisant une chaîne de 11 échoue également, qui suit la même logique, qui fait que tout le match "", ce qui signifie probablement qu'il correspond à une seule fois, ce qui (?(a)(?!)) à l'échec.

+0

Belle analyse, merci! Je vais voir si je peux corriger cela ... =) – Jens

0

Avec l'entrée de Joel, j'ai réussi à le faire fonctionner, en modifiant légèrement l'algorithme pour éviter les lignes (?<b-c>)*.

Voici:

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

Je voudrais donner un lien ideone, mais le résultat je reçois là-bas diffère de la mienne. Peut-être parce que j'utilise. NET 4.0 et ils ne le font pas?

+0

Cela échoue toujours sur le cas de '11', mais je n'ai pas trouvé d'autre cas de défaillance pour cela. –