查找模式,但不在C ++注释中

时间:2019-01-23 21:11:30

标签: regex regex-negation

我有一个正则表达式,可以在大型代码库中搜索用作类型或变量的特定令牌的用法。假设令牌是“ 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样式注释(/ * * /)或跨多行的任何内容。

2 个答案:

答案 0 :(得分:1)

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

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

您可以快速创建在90%的情况下都可以使用的东西,但是如果您要正确处理嵌套的注释或看起来像注释的字符串,则解析是唯一的选择。

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

答案 1 :(得分: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