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:
答案 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,坏主意。