例如,我们在文件中包含以下内容:
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)
之后)可以解决这个问题,但事实并非如此。
有没有人有任何聪明的想法?
答案 0 :(得分: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).)*
使用选项-oM
,得到了这个结果:
START OF NEW LOG ENTRY
START
first line
second line KEYWORD
third line
START
first line
second line KEYWORD
third line
...确认第二次比赛尝试在第二行开始,而不是在比赛的最后一行之后。使用选项-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).)*$
它更有效率,它纠正了tempered greedy token中的错误:在前瞻之后,点必须,而不是之前。