使用 grep 匹配一个句子

使用 grep 匹配一个句子

我正在尝试 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 的回答更加简单,我不确定我在测试中是如何跳过它的。我将这些解决方案留在这里以供其他人参考;特别是第二个解决方案,适合那些正在寻找更复杂输入的人。

相关内容