POSIX 正则表达式 - 括号表达式的零个或一个匹配项?

POSIX regex - zero or one matches of bracket expression?

我正在尝试使用正则表达式来解析源文件并在 C 程序中搜索以单词 "LOG" 开头并且可能后跟也可能不跟 [=18= 中的第二个字符的函数] [1248AFM],然后是左括号。这是在 Windows 下使用 mingw 开发的,但最终将在 Linux 下使用 gcc 进行编译和 运行。我正在使用 Jan Goyvaerts 正则表达式教程作为指南,看起来我所追求的是上面显示的括号表达式表达式的零个或一个匹配项。零或一个听起来很像问号元字符,但在我的实验中,我还没有能够让它在括号表达式后工作。为了说明我正在尝试做的事情,我有如下所示的短程序。理想情况下,我只想在 str1 和 str2 上进行匹配。如果我编译并 运行 它如图所示,我没有得到任何匹配项。如果我在方括号表达式后面省略问号,我只会在 str2 上得到匹配,这正是我所期望的。除了问号之外,我还尝试了 {0,1} 形式的区间量词,但也没有成功。我应该使用除括号表达式以外的其他东西吗?

戴夫

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

int main(int argc, char **argv) {
  regex_t regex;
  int rtn = regcomp(&regex, "LOG[1248AFM]?(", 0);
  if (rtn) {
    printf("compile failed\n");
    return(1);
  }
  char *str1 = "  LOG(";
  char *str2 = "  LOGM(";
  char *str3 = "  LOG";
  char *str4 = "  LOGJ(";

  int rtn1 = regexec(&regex, str1, 0, NULL, 0);
  int rtn2 = regexec(&regex, str2, 0, NULL, 0);
  int rtn3 = regexec(&regex, str3, 0, NULL, 0);
  int rtn4 = regexec(&regex, str4, 0, NULL, 0);
  printf("str1: %d\nstr2: %d\nstr3: %d\nstr4: %d\n",
    rtn1, rtn2, rtn3, rtn4);

  return(0);
}

就像 Casimir et Hippolyte 说的:你需要逃避 ? ,当我发表评论时,我逃脱了。问题是你使用了字符串字面量,这意味着你必须转义。

EDIT 正如用户 kdhp 正确指出的那样:? 是基本正则表达式的 Gnu 扩展。但问题仍然存在:需要对 C 文字中的转义符进行转义。

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

int main(int argc, char **argv) {
  regex_t regex;
  // Gnu extension
  // int rtn = regcomp(&regex, "LOG[1248AFM]\?(",0);
  // Basic regular expression
  int rtn = regcomp(&regex, "LOG[1248AFM]\{0,1\}(",0);
  if (rtn) {
    printf("compile failed\n");
    return(1);
  }
  char *str1 = "  LOG(";
  char *str2 = "  LOGM(";
  char *str3 = "  LOG";
  char *str4 = "  LOGJ(";

  int rtn1 = regexec(&regex, str1, 0, NULL, 0);
  int rtn2 = regexec(&regex, str2, 0, NULL, 0);
  int rtn3 = regexec(&regex, str3, 0, NULL, 0);
  int rtn4 = regexec(&regex, str4, 0, NULL, 0);
  printf("str1: %d\nstr2: %d\nstr3: %d\nstr4: %d\n",
    rtn1, rtn2, rtn3, rtn4);

  return(0);
}

给予

str1: 0
str2: 0
str3: 1
str4: 1

这里的部分问题源于不同正则表达式方言的功能集之间不幸的混淆。

长话短说,使用 REG_EXTENDED,您可以获得某些正则表达式结构的 grep -E(又名 egrep)含义。

"e?(grep){3,7}"

其中不需要反斜杠 -- 问号 ? 使前面的表达式可选,圆括号进行分组,花括号表示一般重复(在本例中,重复三到七次)。

如果没有 REG_EXTENDED,您将获得 BRE 语义,这需要在每个语义之前加一个反斜杠。在C字符串中,当然要产生文字反斜杠,就需要两个反斜杠,因为反斜杠是一般的C字符串转义字符。

"e\?\(grep\)\{3,7\}"

下面是对历史的简要解释,但您可以在这里停止阅读并完成。

基本正则表达式 (BRE) 基于 Ken Thompson 最初 grep 的特征集。原来的 grep 没有分组括号,没有大括号的广义量化,甚至没有表示可选性的问号。然而,POSIX 标准编纂了一种表达这些结构的方法,即使在 BRE 中也是如此。等一下。

扩展正则表达式 (ERE) 基于 egrep 的功能集,后者主要由 Al Aho 对 grep 进行扩展。它引入了许多新功能,以及不同的内部架构,基于当时对自动机理论在字符串匹配中的应用的持续研究(我们在这里谈论的是 70 年代初期到中期)。

当这些被 POSIX 标准化时,该标准引入了功能对等,但这些方言具有不同的表面句法。 grep 语法的一个有点古怪的扩展,其中反斜杠 enable, 而不是 escape, 一些字符的特殊含义,被引入在 BRE 方言中。这使得 BRE 向后兼容原始的 grep(只要您没有在正则表达式中不必要地使用反斜杠,而以前反斜杠没有特殊含义),这是一个重要的考虑因素,但不可否认这是一个设计缺陷。