1
        Regex regexObj = new Regex(
        @"([A-Za-z_][A-Za-z_0-9]*)(:)(([-+*%])?(\d*\.?\d*)?)*"
           , RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);

        var subjectString = "a:123+456;b:456;";
        Match matchResults = regexObj.Match(subjectString);
        while (matchResults.Success) {
            for (int i = 1; i < matchResults.Groups.Count; i++) {
                Group grp = matchResults.Groups[i];
                if (grp.Success) {
                    Console.WriteLine("st:" + grp.Index + ", len:" + grp.Length + ", val:" + grp.Value);
                }
            }
            matchResults = matchResults.NextMatch();
        }

输出:

st:0,len:2,val:.a

st:2, 长度:1, val::

st:6,len:0,val:

st:6,len:0,val:

4

1 回答 1

2

因为通过允许它将“”视为 的有效履行\d*,您的捕获在数字出现之前完成。

您应该至少将一位数字指定为强制 (+) 而不是可选 (*) 以使其开始捕获组。

澄清一下,当正则表达式编译时没有错误,但没有为特定组捕获任何内容,这并不意味着匹配不成功。

这意味着尽管捕获了任何东西,但比赛还是成功了。这意味着您在设计上让它越过该组。

例如,在你自己的正则表达式中:(([-+*%])?(\d*\.?\d*)?)*你说的是:我期待一些可选的符号后跟一个十进制数,即使这也是可选的。如果什么都没找到,那也没关系,所以,亲爱的 RegExp 引擎,请不要打扰自己,因为我不在乎这是否发生。

让我们进一步分解:

  • \d*\.\d*表示任何具有任意位数(包括根本没有)的任何数字,中间有一个点。所以, 0., ., .123, 都是有效匹配,还有2.1.
  • 通过将设为可选,您的意思是即使也不是必需的,因此(\d*\.\d*)?会匹配""(空字符串)。
  • 通过写作([-+*%])?(\d*\.?\d*)?,您是说如果在上面匹配的字符串之前发生任何事情,它必须是四个指示符号之一。但是,您不需要它必须发生(因为?)。此外,由于上述组可以匹配空字符串,如果引擎无法成功地将字符串匹配到任何有用的内容,则指示的四个符号中的任何一个的存在都意味着该组仍然是成功的匹配。全部,包括数字。
  • 现在,通过将先前的定义分组为(([-+*%])?(\d*\.?\d*)?)*,您甚至可以使那个可选,基本上告诉正则表达式引擎,如果它没有比这个定义的开头更进一步寻找答案,那就没问题了。

那么,你应该如何进行呢?你什么时候应该让一个组成为可选的?您应该只谨慎地使一个组成为可选组,知道如果引擎无法将任何内容与该组匹配,则该语句仍然有效并且您不关心该值。

另外,作为旁注,您不应该捕获几乎所有内容。只捕获对您来说很重要的值,因为引擎将为(start,length)您在内存中请求的任何组保存对,这会降低您的性能。代替正常的分组(),使用非捕获组指示器(?:),这将允许您进行分组和更高级别的控制,同时保留内存。

捕获组的另一个用途是当您想要在正则表达式中引用匹配的内容时:

<(\w+)>.*?</\1>

这将捕获具有匹配结束标记的 XML 标记。另请注意,上面的示例仅用于演示,一般来说,使用正则表达式(除了最普通的表达式)解析任何类型的分层文档是大写 B,大写 I,Bad Idea。

于 2012-10-20T07:03:00.930 回答