C - regexec returns NOMATCH - 即使它应该?
C - regexec returns NOMATCH - even though it should?
正则表达式模式需要匹配以下内容:
abc_xyz_0
abc_1025_01.29.00_xyz_0
abc_0302_42.01.00_xyz_0
(abc 和 xyz 之间的数字无关紧要)
所以我解析为:
(abc_(\w+\.\d+\.\w+)?xyz_0)
我的代码:
regex_t r;
unsigned int maxGroups = 3;
regmatch_t groupArray[maxGroups];
char * to_match = "abc_0302_02.01.00_xyz_18 abc_0302_02.01.00_xyz_16 abc_0302_02.01.00_xyz_14 abc_0302_02.01.00_xyz_0 abc_0302_02.01.00_xyz_10 abc_0302_02.01.00_xyz_2"
if (0 != regcomp(&r, "(abc_(\w+\.\d+\.\w+)?xyz_0)", REG_EXTENDED))
{
//this does NOT get hit
printf("regcomp failed")
}
else if(regexec(r, to_match, maxGroups, groupArray, REG_EXTENDED) == 0)
{ *never gets here* }
else
{ printf("regexec returned non-zero(No Matches)\n"); }
regfree(&r);
所以我的猜测是我的正则表达式有误(这对我上面定义的情况很好 - 我用 regexpal.com 来确认),或者我遗漏了什么?
无论哪种方式,我都知道我很接近,非常感谢您的帮助。
您复制到问题中的代码中有几个错别字(见下文),您应该只将 REG_EXTENDED
传递给 regcomp
; regexec
识别的唯一标志是 REG_NOTBOL
和 REG_NOTEOL
。 (详见 regexec
manpage。)
但是,问题是 Posix 正则表达式(包括 Gnu 实现)没有实现 non-standard 转义序列 \d
。如 regex(7)
manpage 中所示,一个模式可以包括:
a '\' followed by one of the characters "^.[$()|*+?{\" (matching that character taken as an ordinary character),
或
a '\' followed by any other character (matching that character taken as an ordinary character, as if the '\' had not been present)
请注意,在任何一种情况下,\
的唯一作用是使后面的字符作为普通字符进行匹配。虽然 regcomp
的 Gnu 实现确实将 \w
识别为字符 class,但 Posix 不需要这种行为,而其他实现可能不会这样做。 (它也没有记录,所以它可能并不总是有效。)而且它不识别 \d
.
如果你使用Posix正则表达式,你应该使用Posix标准字符classes,所以正则表达式字符串应该是:
"(abc_([[:alnum:]_]+\.[[:digit:]]+\.[[:alnum:]_]+)?xyz_0)"
您将在上一个 link 的正则表达式联机帮助页中找到 Posix 命名字符 classes 的列表(或者假设您已安装,则键入 man 7 regex
标准库文档,强烈推荐。)
我用你的代码验证了这一点,在 char * to_match =...
末尾添加了缺失的分号,并在对 regexec
的调用中将 r
更改为 &r
。
请注意,很少有在线正则表达式资源实现 Posix 正则表达式规范; http://regexpal.com,例如,只提供了PCRE-和Javascript-style正则表达式的选项。
每次调用 regexec
,根据 man 7 regex
:
中描述的固定算法,您将获得传递给它的字符串中的第一个匹配项
In the event that an RE could match more than one substring of a
given string, the RE matches the one starting earliest in the string.
If the RE could match more than one substring starting at that point,
it matches the longest. Subexpressions also match the longest
possible substrings, subject to the constraint that the whole match
be as long as possible, with subexpressions starting earlier in the
RE taking priority over ones starting later. Note that higher-level
subexpressions thus take priority over their lower-level component
subexpressions.
如果你想在同一个字符串中找到一个模式的多个实例,你需要在循环中调用regexec
。每次通过循环,您都会将前一个匹配项(即 string + matches[0].rm_eo
)中第一个不匹配字节的地址提供给它,直到它报告不再有匹配项为止。如果您在比赛中依赖 ^
锚点,则需要将 REG_NOTBOL
标志的正确值传递给对 regexec
.
的每次调用
正则表达式模式需要匹配以下内容:
abc_xyz_0
abc_1025_01.29.00_xyz_0
abc_0302_42.01.00_xyz_0
(abc 和 xyz 之间的数字无关紧要)
所以我解析为:
(abc_(\w+\.\d+\.\w+)?xyz_0)
我的代码:
regex_t r;
unsigned int maxGroups = 3;
regmatch_t groupArray[maxGroups];
char * to_match = "abc_0302_02.01.00_xyz_18 abc_0302_02.01.00_xyz_16 abc_0302_02.01.00_xyz_14 abc_0302_02.01.00_xyz_0 abc_0302_02.01.00_xyz_10 abc_0302_02.01.00_xyz_2"
if (0 != regcomp(&r, "(abc_(\w+\.\d+\.\w+)?xyz_0)", REG_EXTENDED))
{
//this does NOT get hit
printf("regcomp failed")
}
else if(regexec(r, to_match, maxGroups, groupArray, REG_EXTENDED) == 0)
{ *never gets here* }
else
{ printf("regexec returned non-zero(No Matches)\n"); }
regfree(&r);
所以我的猜测是我的正则表达式有误(这对我上面定义的情况很好 - 我用 regexpal.com 来确认),或者我遗漏了什么?
无论哪种方式,我都知道我很接近,非常感谢您的帮助。
您复制到问题中的代码中有几个错别字(见下文),您应该只将 REG_EXTENDED
传递给 regcomp
; regexec
识别的唯一标志是 REG_NOTBOL
和 REG_NOTEOL
。 (详见 regexec
manpage。)
但是,问题是 Posix 正则表达式(包括 Gnu 实现)没有实现 non-standard 转义序列 \d
。如 regex(7)
manpage 中所示,一个模式可以包括:
a '\' followed by one of the characters "^.[$()|*+?{\" (matching that character taken as an ordinary character),
或
a '\' followed by any other character (matching that character taken as an ordinary character, as if the '\' had not been present)
请注意,在任何一种情况下,\
的唯一作用是使后面的字符作为普通字符进行匹配。虽然 regcomp
的 Gnu 实现确实将 \w
识别为字符 class,但 Posix 不需要这种行为,而其他实现可能不会这样做。 (它也没有记录,所以它可能并不总是有效。)而且它不识别 \d
.
如果你使用Posix正则表达式,你应该使用Posix标准字符classes,所以正则表达式字符串应该是:
"(abc_([[:alnum:]_]+\.[[:digit:]]+\.[[:alnum:]_]+)?xyz_0)"
您将在上一个 link 的正则表达式联机帮助页中找到 Posix 命名字符 classes 的列表(或者假设您已安装,则键入 man 7 regex
标准库文档,强烈推荐。)
我用你的代码验证了这一点,在 char * to_match =...
末尾添加了缺失的分号,并在对 regexec
的调用中将 r
更改为 &r
。
请注意,很少有在线正则表达式资源实现 Posix 正则表达式规范; http://regexpal.com,例如,只提供了PCRE-和Javascript-style正则表达式的选项。
每次调用 regexec
,根据 man 7 regex
:
In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, it matches the longest. Subexpressions also match the longest possible substrings, subject to the constraint that the whole match be as long as possible, with subexpressions starting earlier in the RE taking priority over ones starting later. Note that higher-level subexpressions thus take priority over their lower-level component subexpressions.
如果你想在同一个字符串中找到一个模式的多个实例,你需要在循环中调用regexec
。每次通过循环,您都会将前一个匹配项(即 string + matches[0].rm_eo
)中第一个不匹配字节的地址提供给它,直到它报告不再有匹配项为止。如果您在比赛中依赖 ^
锚点,则需要将 REG_NOTBOL
标志的正确值传递给对 regexec
.