【问题标题】:POSIX regex - zero or one matches of bracket expression?POSIX 正则表达式 - 括号表达式的零个或一个匹配?
【发布时间】:2016-09-05 16:30:00
【问题描述】:

我正在尝试使用正则表达式来解析源文件并在 C 程序中搜索以单词“LOG”开头的函数,并且可能会或可能不会后跟来自类 [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);
}

【问题讨论】:

  • 在 basic 中似乎不起作用,请尝试 int rtn = regcomp(&amp;regex, "LOG[1248AFM]?[(]", REG_EXTENDED); 代替(扩展使用括号作为组分隔符,因此使用方括号)。
  • 在 BRE 中 ? 必须转义 \? (如果支持)
  • Casimir - 我已经尝试过了,但是编译失败了。
  • deamentiaemundi - 我没有想到这一点,你是绝对正确的 - 它工作得很好。谢谢!
  • @deamentiaemundi - 您能否将您的评论重新发布为答案,以便我标记它?在这一点上,我没有足够的声誉来支持评论。

标签: c regex posix


【解决方案1】:

就像 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

【讨论】:

  • 也许答案还应该解释支持的正则表达式方言之间的根本区别,即 BRE 与 ERE?
  • @tripleee 我不是语言学家,我也不知道方言的肥料。我是一名程序员,所以我确实知道,当我选择正则表达式来解决问题的那一刻,我马上就会遇到两个问题。此外:最大帖子长度为 30k IIRC
  • \? 的使用是 POSIX BRE 的 GNU 扩展。 ERE (REG_EXTENDED) 或括号表达式 (\{0,1\}) 可用于可移植性。
  • @kdhp Argh,我爱上了它!谢谢。会改正的。
  • 你的意思是你不明白REG_EXTENDED标志的含义吗?正如几个 cmets 所指出的,使用它会提供一种不同的解决方案,在某些方面会更优雅,并且希望能解决原始问题中的误解。
【解决方案2】:

这里的部分问题源于不同正则表达式方言的特征集之间令人遗憾的混淆。

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

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

不需要反斜杠 - 问号? 使前面的表达式可选,括号进行分组,大括号表示一般重复(在这种情况下,重复三到七次)。

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

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

以下是对历史的简要说明,但您可以在此处停止阅读并完成。

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

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多