我正在尝试使用C来匹配以十六进制格式的以下ASCII字符范围:\x21
/ \x23-\x2B
/ \x2D-\x39
/ \x3C-\x5B
/ \x5D-\x7E
< / p>
我发现此函数在another stack overflow answer上的C中与正则表达式匹配:
int match(const char *string, char *pattern) {
int status;
regex_t regex;
int d;
if ((d = regcomp(®ex, pattern, REG_EXTENDED | REG_NOSUB)) != 0) {
return 0;
}
status = regexec(®ex, string, (size_t)0, NULL, 0);
regfree(®ex);
if (status != 0) {
return 0;
}
return (1);
}
如果字符串与给定模式不匹配,则此函数将返回0;如果字符串不匹配,则返回1.
除了我尝试匹配多个十六进制值范围时,此函数适用于大多数模式。
例如:
int main(int argc, char const *argv[]) {
printf("%d\n", match("HELLO!", "^[\x21 \x23-\x2B \x2D-\x39 \x3C-\x5B]+$")); // Matches as expected
printf("%d\n", match("hello!", "^[\x21 \x23-\x2B \x2D-\x39 \x3C-\x5B]+$")); // Fails as expected because we are not including lower case letters
printf("%d\n", match("HELLO!", "^[\x21 \x23-\x2B \x2D-\x39 \x3C-\x5B \x5D-\x7E]+$")); // Fails unexpectedly after adding 5D-7E
printf("%d\n", match("hello!", "^[\x21 \x23-\x2B \x2D-\x39 \x3C-\x5B \x5D-\x7E]+$")); // Fails unexpectedly but should pass because we have added 5D-7E which includes lower case letters
printf("%d\n", match("hello", "^[\x5D-\x7E]+$")); // Matches as expected because we have included lower case range
}
将输出:
1 // Expected
0 // Expected
0 // Unexpected
0 // Unexpected
1 // Expected
似乎将5D-7E范围添加到任何其他范围会打破正则表达式。
我错过了什么或者这看起来很奇怪吗?
可以看到一个供参考的ASCII表here。
答案 0 :(得分:2)
\x5D
是一个小括号(] )。也就是说,它确实是一个紧密的支柱;在程序文本被解析之前完成替换,就像所有其余的反斜杠转义一样。所以你的字符串
"^[\x21 \x23-\x2B \x2D-\x39 \x3C-\x5B \x5D-\x7E]+$"
实际上是字符串
"^[! #-+ --9 <-[ ]-~]+$"
这就是regcomp
编译的内容。 [注1]
该模式有三个问题,其中一个应该是显而易见的:字符类由第一个] 终止,所以匹配的是匹配字符类的单个字符[! #-+ --9 <-[ ]
,后面依次为 - 〜,然后是一个或多个] 字符。显然,HELLO!
与此模式不匹配。
其次,字符类中的空格字符不是特殊的,这意味着它不会被忽略(我相信你期望)。因此,字符类中读取--9
的部分实际上意味着“空格(0x20)和短划线(0x2D)之间的任何字符或字符 9 ”。
与此相关,即使您删除了空格(您肯定需要这样做),--9
也不合法,因为作为文字字符的 - 只能出现在字符类的开头或结尾。 [注2]
最后,角色类[\x5D-\x7E]
做你做了什么,因为如果它是第一个字符,那么允许] 作为文字字符显示字符类,在这种情况下是([]-~]
)
这些规则记录在regex manpage中,并在Posix Base Definitions Section 9中详细说明。
您可以通过反斜杠转义("\\x5D"
)来提供反斜杠作为正则表达式字符串的一部分,但这不适用于Posix正则表达式,因为Posix规范不包含十六进制转义序列,也不是标准的C转义符,例如\n
。如联机帮助页中所述,Gnu C库正则表达式实现将\x
理解为文字x
并将\n
理解为文字n
(与反斜杠后跟任何字母相同)字符)。但是,Posix没有定义这些用法;在Posix扩展正则表达式中,反斜杠只能用于转义特殊字符,并且只能用于字符类之外。
虽然标准未定义用法,但正则表达式库可能会将-
识别为文字字符,因为它会立即显示在字符范围之后。但是,依赖这样的扩展是不好的做法,即使它们碰巧在特定的Posix库实现上工作。