1

因此,例如,我们在文件中有以下内容:

START OF NEW LOG ENTRY
first line
second line KEYWORD
third line
START OF NEW LOG ENTRY
first line
second line
third line
etc... (this file goes on in this manner for a long time)
...

我需要提取每个日志条目中包含关键字“KEYWORD”的所有行。相应的正则表达式(使用 pcregrep)如下:

pcregrep -Mo "(?s)(?:^START OF NEW LOG ENTRY)(?:.(?!^START OF NEW LOG ENTRY))*?(?:KEYWORD).*?(?=\nSTART OF NEW LOG ENTRY|\Z)" file

现在这工作得很好,并按预期打印以下内容:

START OF NEW LOG ENTRY
first line
second line KEYWORD
third line

那么怎么了?...好吧,我的理解是,正则表达式的工作原理是,在匹配该日志条目(第 1-4 行)之后,正则表达式引擎开始尝试从第 2 行再次匹配,因此正则表达式引擎不必要地遍历 2 行从第二个日志条目的开头开始匹配时的字符,这似乎是浪费时间 - 我们应该继续最后一次匹配结束的地方,即第 5 行。

我认为放置\G在我的正则表达式的开头(在 之后(?s))可以解决这个问题,但事实并非如此。

有没有人有任何聪明的想法?

4

1 回答 1

0

使用-C0代替-o对我有用。我使用此修改后的输入确认了问题:

START OF NEW LOG ENTRY
first line
START
second line KEYWORD
third line
START OF NEW LOG ENTRY
first line
second line
third line
etc... (this file goes on in this manner for a long time)
...

...和这个正则表达式:

(?s)^START.*?KEYWORD(?:(?!^START).)*

使用 options -oM,它得到了这个结果:

START OF NEW LOG ENTRY
START
first line
second line KEYWORD
third line

START
first line
second line KEYWORD
third line

...确认第二次匹配尝试从第二行开始,而不是在匹配的最后一行之后。使用 options -C0 -M,它只得到一击,根据需要:

START OF NEW LOG ENTRY
START
first line
second line KEYWORD
third line

-o仅打印匹配的内容,而不是整行加上上下文。但它也允许每行有多个匹配项,我猜这就是问题的根源。无论如何,您的正则表达式匹配整行,因此您需要做的就是抑制上下文。

这是我将使用的实际正则表达式:

(?s)^START OF NEW LOG ENTRY(?:(?!^START OF NEW LOG ENTRY|\bKEYWORD\b).)*+\bKEYWORD\b(?:(?!^START OF NEW LOG ENTRY).)*$

它的效率更高一点,它纠正了缓和的贪婪令牌中的错误:点必须前瞻之后,而不是之前。

于 2016-09-10T04:56:37.093 回答