C POSIX 正则表达式失败

C POSIX Regular Expression failure

我正在尝试在 C 编程语言中使用 POSIX 正则表达式。

我有这些正则表达式模式:

const char *regular_expression_pattern_keyword = "^(auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)";
const char *regular_expression_pattern_identifier = "^[:word:]";
const char *regular_expression_pattern_number = "^[:digit:]*";
const char *regular_expression_pattern_punctuator = "^[:punct:]";

要检查雷鬼,我有一个功能:

char **patterns = malloc ((sizeof (char) * 256) * 4);

patterns[0] = (char *) regular_expression_pattern_keyword;
patterns[1] = (char *) regular_expression_pattern_identifier;
patterns[2] = (char *) regular_expression_pattern_number;
patterns[3] = (char *) regular_expression_pattern_punctuator;

for (int i = 0; i < 4; i++)
{
    regex_t regular_expression;
    int status;

    status = regcomp(&regular_expression, patterns[i], 0);

    if (status)
    {
        // FIXME: Improve error handling!
        printf("Error: Failed to compile regex!\n");
        exit(1);
    }

    status = regexec(&regular_expression, "auto", 0, NULL, 0);

    if (!status)
    {
        printf("Regex status: Match ->%s\n", patterns[i]);
    }

    else if (status == REG_NOMATCH)
    {
        printf("Regex status: No match\n");
    }

    else
    {
        // FIXME: Improve error handling!
        printf("Error: Failed to match regex!\n");
        exit(1);
    }

    regfree(&regular_expression);
}

free (patterns);

由于我不知道的原因,此雷鬼检查将 auto 匹配为 Regex status: Match ->^[:digit:]*。我做错了什么?

您的代码中有 未定义的行为malloc 调用和以下赋值没有按照您的预期进行。

malloc 调用分配了 1024 (256 * 4) 个连续字节,而不是指针数组(类似于 char **)。

你不需要在这里动态分配任何东西,只需要声明一个指针数组,比如

const char *patterns[] = {
    regular_expression_pattern_keyword,
    regular_expression_pattern_identifier,
    regular_expression_pattern_number,
    regular_expression_pattern_punctuator
};

这里有几点需要注意:

  • [:digit:] 和其他 POSIX 字符 classes 必须在方括号 ("character") classes 内使用(例如 [[:digit:]]), 并不孤单。否则,它们匹配来自 class 的不同符号,即 [:digit:] 匹配 1 个符号,或者 :,或者 dig,或 t.

  • 要对 quantifying/grouping 使用交替和未转义的 brackets/parentheses,您需要使用 REG_EXTENDED 标志和 regcomp 来使用 ERE 正则表达式语法。如果不传递此标志,您使用的是 BRE 正则表达式语法,这是相当糟糕的。

现在,为什么 ^[:digit:]* 匹配 auto?因为您要求正则表达式引擎查找 个或更多字符,所以 :digt。它确实在字符串的开头找到了零个这样的字符,因此,你有一个匹配项。

^[[:digit:]]\{1,\} match 1ab which is not a number at all

不,模式不匹配 1ab,它只匹配 1ab 中的 1 因为您没有指定任何 边界 或锚.

要仅匹配字符串开头的数字(=数字序列),请使用

"^[[:digit:]]+(\W|$)" (or "^[[:digit:]]+([^[:digit:][:alpha:]_]|$)"

不要忘记将 REG_EXTENDED 标志传递给 regcomp 函数。

参见 this demo。请注意,在 ERE 正则表达式语法中,您可以使用 + 来匹配 1 个或多个字符,而在 BRE(没有 REG_EXTENDED)中,您必须使用 \{1,\}.