1

我有一个正则表达式,可以搜索大型代码库以查找用作类型或变量的特定令牌的使用情况。假设令牌是“foo”,我想将其作为作品本身来查找。

我最初的正则表达式是这样的:

foo$|foo\s|foo\[|foo\*|<foo|foo>

匹配: foo 在行尾, foo 带有空格, foo 指针, foo 在集合中,等等...

我想排除C++ 注释框中的实例。比如下面的例子。

// consume the foo and read another.

我尝试使用负前瞻来修改正则表达式,但这似乎不起作用

(?!\/\/).*(foo$|foo\s|foo\[|foo\*|<foo|foo>)

任何人都知道如何在正则表达式中做到这一点?

更新:

我只是想随便过滤掉在目标模式之前可能有两个正斜杠的行。我不关心嵌套注释、C 风格注释 (/* */) 或任何跨越多行的内容。

4

2 回答 2

1

正则表达式不是最好的工具。

我写了一个 C 到 Delphi 转换器 ( https://github.com/WouterVanNifterick/C-To-Delphi ),我确实在某些任务中使用正则表达式,但我的结论是正则表达式不是正确的工具对于你想要做的事情。我可以说出来,因为我已经尝试过了,并决定放弃正则表达式,因为事情变得过于复杂并且事情不能可靠地工作。

您可以快速创建适用于 90% 情况的内容,但如果您想正确处理嵌套注释或看起来像注释的字符串,解析是唯一的选择。

您不需要完整的 C++ 解析器。您需要遍历所有字符,并跟踪您是否在 /* */ 块、"" 字符串块或 // 部分中,并执行您需要执行的操作。

于 2019-01-23T21:23:44.603 回答
1

这是您所要求的相当全面的正则表达式(在 Perl 中测试):

my $foo_regex = qr{
    \G
    (?>
        # // comment
        / (?: \\ \n )*+ / (?> \\ \n | [^\n] )*+
    |
        # /* comment */
        / (?: \\ \n )*+ \* (?> .*? \* (?: \\ \n )*+ / )
    |
        # 'c'
        ' (?: [^'\\\n] | \\ . )++ '
    |
        # "string"
        " (?: [^"\\\n] | \\ . )*+ "
    |
        # R"(raw string)"
        \b
        (?: (?> [LU] | u (?: \\ \n )*+ 8?+ ) (?: \\ \n )*+ )?+
        R
        (?: \\ \n )*+
        "
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        \(
        (?>
            .*?
            \)
            (?: \\ \n )*+
            \g{-16}
            (?: \\ \n )*+
            \g{-15}
            (?: \\ \n )*+
            \g{-14}
            (?: \\ \n )*+
            \g{-13}
            (?: \\ \n )*+
            \g{-12}
            (?: \\ \n )*+
            \g{-11}
            (?: \\ \n )*+
            \g{-10}
            (?: \\ \n )*+
            \g{-9}
            (?: \\ \n )*+
            \g{-8}
            (?: \\ \n )*+
            \g{-7}
            (?: \\ \n )*+
            \g{-6}
            (?: \\ \n )*+
            \g{-5}
            (?: \\ \n )*+
            \g{-4}
            (?: \\ \n )*+
            \g{-3}
            (?: \\ \n )*+
            \g{-2}
            (?: \\ \n )*+
            \g{-1}
            (?: \\ \n )*+
            "
        )
    |
        # / (not starting a comment)
        / (?! (?: \\ \n )*+ [/*] )
    |
        # identifier
        \w (?: (?: \\ \n )*+ \w )*+
    |
        # arbitrary other character
        [^/"'\w]
    )*?
    \b
    (
        f
        (?: \\ \n )*+
        o
        (?: \\ \n )*+
        o
    )
    (?!
        (?: \\ \n )*+
        \w
    )
}xms;

它考虑的并发症概述:

  • "foo", 'foo', // foo,/* foo */不是foo, 而是字符串文字、多字符常量、单行注释和块注释。
  • /* " */, // ", " /* ",'//'等分别是注释、注释、字符串文字和多字符常量。这意味着您不能分阶段过滤掉字符串文字、注释等;您必须一次全部解析它们,以避免将引用构造的内容误认为是另一个引用构造的分隔符。
  • 必须忽略反斜杠换行符组合(就像源文件中不存在它们一样):

      /\
      * this is a comment */
      /\
      / and so is this
      foo\
      bar  // this is a single identifier, 'foobar'
      f\
      oo  // ... but this is 'foo'
      "this is a string\\
      " <- that's not the end of the string; this is: "
    
  • 这个正则表达式的很大一部分处理形式的原始字符串文字,R"delim(...)delim"并结合了可以散布在任何地方的任意反斜杠换行符对。幸运的是,C++ 指定了最多 16 个自定义分隔符的上限;否则我们将不得不使用运行时代码执行/动态正则表达式生成。
  • 不处理三元组。如果要添加支持,请首先\\将正则表达式中的每个出现更改为(?> \\ | \?\?/ ).

更新:对于您的简化要求(在字符串中找到foo前面没有的单词),您可以简单地执行.//^(?:[^/]|/(?!/))*?\bfoo\b

于 2019-01-23T22:38:33.693 回答