我正在尝试TODO
使用正则表达式匹配某些代码文件中的内部注释等标签。例如考虑以下文件:
foo bar # TODO
bar foo quux # TODO bar # TODO foo quux
quux # foo ## TODO foo # bar # TODO quux
'# TODO\'' # TODO
请注意,一行中可能有多个标签,只要每个标签前面都有#
,因此第二行和第三行应该匹配两次。此外,第一个#
(实际代码)之前的前缀可能具有任意长度;这同样适用于每个 之后的内容TODO
。除此之外,可能# TODO
还有没有注释的子字符串(见第四行;它应该匹配一次,# TODO
最后的)。
我一直在 Stackoverflow 和其他网站上搜索,但似乎没有任何问题可以回答您在这些匹配之前有多个重叠匹配和可变长度前缀的问题。我认为问题主要在于尝试结合上下文使用积极的前瞻/后瞻:
(?=#\s*TODO[^#]*)
不起作用,因为它匹配第四行两次。这就是我说重叠的原因:看起来你必须在匹配时考虑前缀的结构。- 我可以匹配前缀(实际代码和没有标签的注释)部分,
^[^#']*('[^'\\]*(\\.[^'\\]*)*'[^#']*)*(#\s*(?!TODO)[^#]*)*
以便我得到正确的第 4 行,但这是一个可变长度匹配,因此使用积极的后(?<=^[^#']*('[^'\\]*(\\.[^'\\]*)*'[^#']*)*(#\s*(?!TODO)[^#]*)*)(#\s*TODO[^#]*)
视将导致每个正则表达式引擎上的错误据我所知(如果工作,无论如何只会匹配第一个# TODO
)。 - 匹配前缀然后使用积极的前瞻类似
^[^#']*('[^'\\]*(\\.[^'\\]*)*'[^#']*)*(#\s*(?!TODO)[^#]*)*(?=(#\s*TODO[^#]*)(#\s*(?!TODO)[^#]*)*)
也不起作用,因为它只匹配# TODO
.
解释一下: \\.
匹配转义字符和[^'\\]*
任何不是转义字符且不是字符串分隔符的内容,因此'[^'\\]*(\\.[^'\\]*)*'
匹配任何字符串文字。在该字符串文字部分之外使用[^#']*
意味着:匹配任何不以字符串或注释开头的内容,因此一行的代码部分是^[^#']*('[^'\\]*(\\.[^'\\]*)*'[^#']*)*
. 可以找到不包含标签的注释段#\s*(?!TODO)[^#]*
,因此可以匹配整个前缀^[^#']*('[^'\\]*(\\.[^'\\]*)*'[^#']*)*(#\s*(?!TODO)[^#]*)*
。
我使用ripgrep
,所以这适用于 PCRE/PCRE2 正则表达式。但是,我会对任何正则表达式方言是否有解决方案感兴趣。
我知道我可以匹配至少有一个正确匹配的每一行,并用某种脚本语言对结果进行后处理以TODO
从这些行中提取每一行,但我想知道是否可以仅使用正则表达式。