【问题标题】:C POSIX ERE without back-references没有反向引用的 C POSIX ERE
【发布时间】:2018-12-13 17:43:58
【问题描述】:

我需要在我的 C 代码中包含一个 POSIX ERE 正则表达式编译器/执行器。我选择了本地 regex.h 库,其内容如下所示:

#include <regex.h>

bool
match_posix_regex(const char *pattern, const char *str){
    regex_t regex;
    int reti;

    reti = regcomp(&regex, pattern, REG_EXTENDED);
    if(reti){
        printf("Could not compile the regex\n");
        return false;
    }

    reti = regexec(&regex, str, 0, NULL, 0);
    if(!reti){
        return true;
    }

    else if (reti == REG_NOMATCH){
        return false;
    }

    else{
        printf("ERROR in regex execution\n");
        return false;
    }
}

我注意到这个实现包括对反向引用的支持。据我了解,POSIX ERE 标准执行not support 反向引用,但是这些标准的许多实现都执行此操作。查看 regex.h docs 似乎我无法禁用此功能。

我不想包含对回溯的支持,因为它不包含在标准中,而且它可能导致灾难性的回溯,如here 所述。

有没有一种方法可以在 C 中编译和运行符合 POSIX ERE 标准的正则表达式,并且 包含反向引用作为一项功能?

【问题讨论】:

  • POSIX 正则表达式不允许反向引用,也不会导致灾难性的回溯。
  • @WiktorStribiżew 我了解 POSIX ERE 标准不允许反向引用,但我无法在 C 中找到不包含此功能的实现。如果你运行上面的代码,它确实可以编译并理解反向引用语法。
  • 在将正则表达式传递到您用来过滤或转义您不想要的非 POSIX 功能的库之前,总是有一个直接的选项来预处理正则表达式。实际上,您将为 POSIX-plus 正则表达式库编写一个去扩展包装器。但是,我会首先四处寻找另一个可以满足您需求的正则表达式库,并考虑从头开始编写一个作为另一个明显的选择。
  • 很好的问题。在阅读regex(7) 后,我以某种方式假设只有 BRE 会支持反向引用,但您的代码证明并非如此!
  • @Tom 我担心你可能是对的,这些是我唯一的解决方案。我希望避免预处理正则表达式或从头开始编写库的雷区。

标签: c regex posix


【解决方案1】:

虽然 ERE 正则表达式不是常规语言(由于括号级别匹配),但这方面不会影响引用,因此应该可以编写一个相当简单的正则表达式,这样,如果一个字符串匹配它,要么它是有效的ERE 没有反向引用或其他扩展,或者它的括号级别不匹配。为此,只需将括号视为普通字符。大部分工作将是为有效的括号表达式编写正则表达式。然后,在尝试编译之前将您的输入字符串与这个固定的正则表达式进行匹配。

我认为以下是括号表达式的正确正则表达式,部分下方带有注释:

\[^?]?(\[\.([^.]|\.[^]])+\.]|\[=([^]=]|=[^]])+=]|\[:([^]:]|:[^]])+:]|[^]])*]
       ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^
       collating symbol      equivalence class   character class     char

“伪 ERE”是:

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

其中$bracket 是上述括号的正则表达式。

【讨论】:

  • 我在拒绝使用反向引用的正则表达式时遇到的一个问题是,一些被当前实现解释为反向引用的东西,例如 \1 实际上在 POSIX ERE 中仍然有效,因此我不想直接拒绝。据我了解,转义的非特殊字符仅被解释为文字(括号表达式之外)。
  • @dsouza: No. Per 9.4.2 ERE Ordinary Characters,“未转义 ('\\') 前面的普通字符的解释未定义, 除非在括号表达式的上下文中(请参阅 ERE 括号表达式)。”如果不是这种情况,将 \1 解释为反向引用的实现不仅有害,而且会主动破坏和不符合,以至于无法处理定义良好的 ERE。在 ERE 中,只有特殊字符在被反斜杠转义时才会成为代表自己的文字。
  • 是的,您对未定义的解释是正确的。我想这可能是我正在寻找的答案。因此,为了确保我理解,我可以编写一个正则表达式来匹配包含任何非特殊字符的字符串,这些非特殊字符前面是括号表达式之外的非转义反斜杠。这些可以安全地被拒绝。我不太了解您的答案中括号不匹配的正则表达式匹配字符串。如果可能的话,你能详细说明一下吗?
  • 从概念上讲,你想要的是一个函数,它接受一个字符串并给出一个答案,它是否是一个有效的正则表达式。您可以自己编写解析器,但如果您可以执行正则表达式匹配来检查它,那就太好了。但是,所有可能的正则表达式的语言都是不规则的,因为它有分组。我的意思是你可以忽略分组并制作一个匹配完整括号表达式的正则表达式,除了括号之外的任何非反斜杠字符,或反斜杠后跟特殊字符,然后将*应用于它.
  • 如果你的候选人匹配这个模式,它要么是有效的 ERE,要么是由于不匹配的括号而无效。特别是它不是带有反向引用的伪 ERE。在第二种情况下(括号不匹配的误报),regcomp 将向您报告错误。
【解决方案2】:

我只是想指出一个我找到的解决方案。确实存在不支持反向引用的 POSIX ERE 实现。您可以通过启用 _GNU_SOURCE 功能测试宏来公开此接口。这允许您使用 RE_SYNTAX_POSIX_MINIMAL_EXTENDED 编译正则表达式。我发现这个记录在here。然后您可以使用re_compile_pattern 函数。

我知道这可能会导致可移植性问题,但我相信大多数系统都应该理解这一点,并且在我的案例中,这个可移植性问题并不是真正的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    • 1970-01-01
    • 2011-10-17
    相关资源
    最近更新 更多