【问题标题】:When using regex in C, \d does not work but [0-9] does在 C 中使用正则表达式时,\d 不起作用,但 [0-9] 起作用
【发布时间】:2016-10-23 17:27:55
【问题描述】:

我不明白为什么包含\d 字符类的正则表达式模式不起作用但[0-9] 起作用。字符类,例如\s(空白字符)和\w(单词字符),可以工作。我的编译器是 gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3。我正在使用 C 正则表达式库。

为什么\d 不起作用?

文本字符串:

const char *text = "148  apples    5 oranges";

对于上面的文本字符串,这个正则表达式不匹配:

const char *rstr = "^\\d+\\s+\\w+\\s+\\d+\\s+\\w+$";

当使用 [0-9] 而不是 \d: 时,此正则表达式匹配:

const char *rstr = "^[0-9]+\\s+\\w+\\s+[0-9]+\\s+\\w+$";



#include <stdio.h>
#include <stdlib.h>
#include <regex.h>

#define N_MATCHES  30

//   output from gcc --version: gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
//   compile command used:  gcc -o tstc_regex tstc_regex.c

const char *text = "148  apples    5 oranges";
  const char *rstr = "^[0-9]+\\s+\\w+\\s+[0-9]+\\s+\\w+$";    // finds match
//const char *rstr = "^\\d+\\s+\\w+\\s+\\d+\\s+\\w+$";        // does not find match

int main(int argc, char**argv)
{
    regex_t   rgx;
    regmatch_t   matches[N_MATCHES];
    int status;
    status = regcomp(&rgx, rstr, REG_EXTENDED | REG_NEWLINE);
    if (status != 0) {
        fprintf(stdout, "regcomp error: %d\n", status);
        return 1;
    }
    status = regexec(&rgx, text, N_MATCHES, matches, 0);
    if (status == REG_NOMATCH) {
        fprintf(stdout, "regexec result: REG_NOMATCH (%d)\n", status);
    }
    else if (status != 0) {
        fprintf(stdout, "regexec error: %d\n", status);
        return 1;
    }
    else {
        fprintf(stdout, "regexec match found: %d\n", status);
    }
    return 0;
}

【问题讨论】:

  • 我猜\d 会匹配d
  • 我没有找到任何说 libc 不支持Shorthand Character Classes
  • 正则表达式的优点之一是有很多风格可供选择。

标签: c regex


【解决方案1】:

根据POSIX regular expression 规范:

普通字符是受支持字符集中的任何字符,但 ERE 特殊字符中列出的 ERE 特殊字符除外。以反斜杠 ('\') 开头的普通字符的解释是未定义的。

因此,唯一可以合法跟随\ 的字符是:

\^    \.    \[    \$    \(    \)    \|
\*    \+    \?    \{    \\

所有这些都匹配转义字符。尝试使用任何其他 PCRE 扩展可能无法正常工作。

【讨论】:

  • @TomKarzes:glibc supports \s and \w but not \d。谜团已揭开。无论如何,它仍然是非标准语法。
  • @TomKarzes: REG_EXTENDED 启用扩展正则表达式 (ERE),这就是我在上面引用的内容。当然,任何特定的实现都可以扩展一些东西,为规范中未定义的任何东西提供任何语义。
  • Alan Moore 指出,看起来 OP 正在获取GNU ERE extensions,其中包括\w\s,但不包括\d
【解决方案2】:

\d 是 perl 和 vim 字符类。

改用:

 const char *rstr = "^[[:digit:]]+\\s+\\w+\\s+[[:digit:]]+\\s+\\w+$"; 

【讨论】:

    【解决方案3】:

    在严格的 POSIX 环境中尝试任何一种模式都可能最终没有匹配项;如果你想让模式真正兼容 POSIX,请使用所有括号表达式:

    const char *rstr = "^[[:digit:]]+[[:space:]]+[[:alpha:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[[:alpha:]]+$";
    

    POSIX Character_classes

    【讨论】:

    • 快速提示:常规空格应该仍然有效,因此模式可以缩短为^[[:digit:]]+ +[[:alpha:]]+ +[[:digit:]]+ +[[:alpha:]]+$
    • 感谢这个例子。当我早些时候尝试这个时,我使用了单括号,这对我来说似乎是POSIX Character_classes 上的表格所指示的。另外,我会使用文字空间,除非我想允许制表符。
    【解决方案4】:

    您使用的正则表达式风格是 GNU ERE,它类似于 POSIX ERE,但有一些额外的功能。其中包括对字符类简写\s\S\w\W 的支持,但 \d\D。您可以找到更多信息here

    【讨论】:

    • 感谢您指出这一点。我忽略了该页面上没有 \d 和 \D。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多