为什么这个正则表达式不会为数字产生一个组/捕获?

时间:2012-10-20 06:59:42

标签: c# regex

        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,len:1,val ::

st:6,len:0,val:

st:6,len:0,val:

1 个答案:

答案 0 :(得分:2)

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

你至少应该指定一个数字作为强制性(+)而不是可选(*),以使其开始捕获该组。

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

这意味着匹配成功尽管已捕获任何内容。这意味着你可以通过设计让它超越那个群体。

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

让我们进一步分解:

  • \d*\.\d*表示任何具有任意位数的数字(包括根本没有数字),中间有一个点。因此,0...123都是有效的匹配,以及2.1
  • 通过 可选,您说即使也不是必需的,因此,(\d*\.\d*)?将匹配""(空字符串)。
  • 通过编写([-+*%])?(\d*\.?\d*)?,您说应该在上面匹配的字符串之前发生任何事情,它必须是四个指示符号之一。但是,你并不是必须发生它(因为?)。此外,由于上面的组可以匹配空字符串,如果引擎没有成功地将字符串与任何有用的字符串匹配,则任何指示的四个符号的存在将意味着该组仍然是成功的匹配。整个,包括数字。
  • 现在,通过将之前的定义分组为(([-+*%])?(\d*\.?\d*)?)*,您甚至可以使用该选项,基本上告诉正则表达式引擎,如果它看起来不比这个定义的开头更好答案。

那么,你该怎么办?你何时应该选择一个团体?你只需要小心选择一个组,知道如果引擎无法匹配该组的任何内容,该语句仍然有效,你不关心这个值。

另外,作为旁注,你不应该捕捉到所有东西。仅捕获对您而言的值,因为引擎将为您在内存中请求的任何组保留(start,length)对,这将使您的性能降低。使用非捕获组指示符()代替正常分组(?:),这将允许您进行分组和更高级别的控制,同时保留内存。

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

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

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