当找到包含*()的模式的多个匹配项时,.NET Regex.Matches的行为不符合预期

时间:2012-05-13 15:00:20

标签: c# .net regex

我的目标是找到文本中某些模式的所有匹配项。 让我们说我的模式是:

h.*o

这意味着我正在搜索以'h'开头的任何文字,以'o'结尾并且中间有任意数量的字符(也为零)。

我的理解是方法Matches()会根据描述提供多个匹配(请参阅MSDN)。

const string input = "hello hllo helo";
Regex regex = new Regex("h.*o");

var result = regex.Matches(input);
foreach (Match match in result)
{
    Console.WriteLine(match.Value);
}

我的期望是:

1. "hello"
2. "hllo"
3. "helo"
4. "hello hllo"
5. "hello hllo helo"

令我惊讶的是,返回的匹配只包含一个字符串 - 整个输入字符串。

"hello hllo helo"

问题:

  1. 哪一个错了:我的期望,我的正则表达还是课堂用法?
  2. 如何实现我的示例中显示的结果?
  3. 提前致谢。

2 个答案:

答案 0 :(得分:3)

* 贪婪 - 它会尝试匹配尽可能多的字符。您可以通过问号跟随它来使其不情愿,但更好的解决方案是,如果o匹配的字符匹配,则从列表中排除.,如下所示:

h[^o]*o

这是一个link对贪婪与不情愿的非常好的解释。

答案 1 :(得分:2)

*贪婪之外,Matches方法只发现非重叠匹配;也就是说,它会从最后一场比赛停止的位置开始查找每个后续比赛。来自MSDN Library

  

通常情况下,正则表达式引擎会开始搜索下一个匹配的确切位置。

因此,即使您使用*?h[^o]*o代替*,它仍然只会找到“hello”,“hllo”和“helo”。

我不知道Regex是否有内置方法可以有效地找到所有匹配指定模式的可能子串,但是你可以自己遍历所有可能的子串并检查每一个是否匹配:

const string input = "hello hllo helo";
Regex regex = new Regex("^h.*o$");

for (int startIndex = 0; startIndex < input.Length - 1; startIndex++)
{
    for (int endIndex = startIndex + 1; endIndex <= input.Length; endIndex++)
    {
        string substring = input.Substring(startIndex, endIndex - startIndex);
        if (regex.IsMatch(substring))
            Console.WriteLine(substring);
    }
}

输出:

hello
hello hllo
hello hllo helo
hllo
hllo helo
helo

请注意,我已将^$添加到正则表达式,以确保它与整个substring匹配,而不仅仅是substring的子字符串。