我必须写一个正则表达式来从文本中获取三个单词。单词用一个空格分隔。我编写的代码并不是所有的序列。 例如,对于文本“一二三四五六”,我只得到两个序列: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();
答案 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}}
使用此模式,您最终会得到预期的结果。