从文本中获取3个单词

时间:2013-01-22 12:27:11

标签: c# regex

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

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

1 个答案:

答案 0 :(得分: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

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

如何解决这个问题?

我们添加了另一个零宽度断言,这次是负向后看(?<![a-zA-Z])。而不是说“只有当这一点跟随模式时才匹配”,而是说“永远不会匹配,如果这个点在模式之前”。因此,我们永远不会在一个字母之前的一个点匹配。例如,ne two three不会返回o,因为它在string pattern = @"(?<![a-zA-Z])(?=(([a-zA-Z]+ ){2}[a-zA-Z]+))"; added ---> ************* 之前。

{{1}}

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