1

我必须编写一个正则表达式才能从文本中获取三个单词。单词用一个空格分隔。我写的代码不是给我所有的序列。例如对于文本“一二三四五六”,我只有两个序列:1.一二三 2.四五六。但我希望我的正则表达式给我所有的序列,所以输出将是:1.一二三 2.二三四 3.三四五。4.四五六。有人可以告诉我我的正则表达式有什么问题吗?这是我的代码:

   string input = "one two three four five six";
   string pattern = @"([a-zA-Z]+ ){2}[a-zA-Z]+";
   Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
   MatchCollection matches = rgx.Matches(input);
   if (matches.Count > 0)
   {
       Console.WriteLine("{0} ({1} matches):", input, matches.Count);
       Console.WriteLine();
       foreach (Match match in matches)
           Console.WriteLine(match.Value);
   }
   Console.ReadLine();
4

1 回答 1

5

您的正则表达式没有任何问题 - 这就是正则表达式的工作方式。当您找到匹配项时,将在您刚刚找到的匹配项的末尾继续搜索下一个匹配项- 匹配项的宽度已消耗

那么,如何解决这个问题?一种方法是让你的比赛不消耗任何东西。您可以通过将原始模式放置在零宽度的正前瞻断言中来做到这一点:

string pattern = @"(?=([a-zA-Z]+ ){2}[a-zA-Z]+)";
added --->         ***                        * 

(?=pattern)说“仅当它紧随其后的是某些匹配时才匹配pattern”-但内容匹配pattern不是整体匹配的一部分,因此不会被消耗。

但是,如果它不是匹配的一部分,它就不会出现在match.Value- 那么你如何获得价值呢?简单 - 只需在原始模式周围添加一个捕获组(即(?=(pattern))),捕获的组将正常显示在您的结果中。

string pattern = @"(?=(([a-zA-Z]+ ){2}[a-zA-Z]+))";
added --->            *                        *

所以现在,你可以foreach像以前一样遍历你的循环,但是match.Value会是空的——你想要的结果在match.Groups[1].Value.

但现在你有另一个问题。你的结果是

one two three
ne two three
e two three
two three four
wo three four

等等。这是因为即使您从单词中途开始,您的模式也会匹配。

如何解决这个问题?

我们添加了另一个零宽度断言,这次是否定的lookbehind : (?<![a-zA-Z])。它不是说“仅当该点后面跟着模式时才匹配”,而是说“如果该点之前有模式,则永远匹配”。因此,我们永远不会匹配一个字母之前的点。不返回,例如,因为它前面是.ne two threeo

string pattern = @"(?<![a-zA-Z])(?=(([a-zA-Z]+ ){2}[a-zA-Z]+))";
added --->         *************

使用这种模式,您最终会得到预期的结果。

于 2013-01-22T12:50:09.417 回答