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