我正在尝试 grep 包含搜索词的完整句子。我试过
grep (^.|\.\s).*searchterm.*(\.\s|\n)
但它不起作用,我不知道为什么。
澄清一下:我希望 stdout 打印搜索词的完整句子。我正在使用 grep 搜索单个文本文件。
例如,如果我的文件有
“Foo blah. Blah blah searchterm blah blah. Foo bar."
我想要 stdout 打印Blah blah searchterm blah blah
答案1
sh
在我的兼容终端上尝试了这个:
$ grep --only-matching --perl-regexp "[^.]*searchterm[^.]*" \
<<< "Foo blah. Blah blah searchterm blah blah. Foo bar."
Blah blah searchterm blah blah
$
可以缩写为grep -oP
。
我认为您提供的正则表达式的问题在于指定.*
您希望它有多贪婪(如 bertieb 所述)。我所做的只是将您的请求从“只要以点结尾的任何内容”重新表述为“任何不是点的内容”
答案2
这是一个有趣的问题,因为乍一看似乎相对简单 - “哦,只需添加 -P 即可进行 PCRE 解析......不,等等。添加一些前瞻和后瞻......负前瞻和后瞻......替换那些贪婪匹配......为什么我达到了 PCRE 回溯限制?嗯......”突然间已经很晚了,我的一壶茶也快喝完了。
解决方案:
假设输入中没有缩写或其他多余的句点。使用sed
换行符替换句点。简单grep
来说搜索词:
$ sed 's/\./\n/g' input.txt | grep searchterm
除了 perl 安装(和输入中的换行符)外,无需做任何假设。用于Lingua::EN::Sentence
提取句子,同时处理缩写等。
$ perl -MLingua::EN::Sentence=get_sentences -ne 'print "$_\n" for grep { /searchterm/ } @{get_sentences($_)}' <(tr '\n' ' ' < input.txt)
(非常感谢Tom Fenech 在 SO 上对此进行了回答)
除了匹配多余的句点之外,这种方法的另一个潜在优势是它还包括最后的句号。这在您的原始问题中没有指定,但根据您使用的输出,它可能会保存附加一个。
请注意,为此您可能必须安装Lingua::EN::Sentence
;如果您有 perl,那么您可能有 cpan 并且可以(sudo)
cpan install Lingua::EN::Sentence
。
这两种方法都有假设,并且使用除普通 grep 之外的工具;而且基本上不会真正修改您的正则表达式。但它们确实完成了描述的工作,至少在我对 lorem ipsum 文本的测试中是如此。
编辑:Felipe Lema 的回答更加简单,我不确定我在测试中是如何跳过它的。我将这些解决方案留在这里以供其他人参考;特别是第二个解决方案,适合那些正在寻找更复杂输入的人。