如何在 grep 中进行非贪婪匹配?

Posted

技术标签:

【中文标题】如何在 grep 中进行非贪婪匹配?【英文标题】:How to do a non-greedy match in grep? 【发布时间】:2011-03-02 22:25:50 【问题描述】:

我想 grep 最短的匹配,模式应该是这样的:

<car ... model=BMW ...>
...
...
...
</car>

... 表示任何字符,输入是多行。

【问题讨论】:

***.com/questions/1732348/1732454#1732454 【参考方案1】:

您正在寻找非贪婪(或懒惰)的匹配。要在正则表达式中获得非贪婪匹配,您需要在量词之后使用修饰符 ?。例如,您可以将.* 更改为.*?

默认情况下grep 不支持非贪婪修饰符,但您可以使用grep -P 来使用Perl 语法。

【讨论】:

eegg: dot all 修饰符也称为多行。它是改变“。”的修饰符。匹配行为以包含换行符(通常不包含)。 grep 中没有这样的修饰符,但pcregrep 中有。 更正:在大多数支持它的正则表达式风格中,允许 . 匹配换行符的模式称为 DOTALLsingle-line 模式; Ruby 是唯一一个称其为 multiline 的。在其他风格中,multiline 是允许锚点(^$)在行边界处匹配的模式。 Ruby 没有等效模式,因为在 Ruby 中它们总是以这种方式工作。 -P 对我来说是一个全新的人,多年来我一直很高兴地挣扎,只使用-E ......浪费了这么多年! - 自我注意:重新阅读手册页作为(甚至更多!)常规的东西,你永远不会消化足够的开关和选项。 在某些平台上(如 Mac OS X)grep 不支持-P,但如果您使用egrep,您可以使用.*? 模式来实现相同的结果。 egrep -o 'start.*?end' text.html 作为@SaltyNuts 评论的扩展,Mac OS X 不支持-P,但-E 会调用egrep,因此建议的.*? 工作正常。【参考方案2】:

实际上.*? 仅适用于perl。我不确定等效的 grep 扩展正则表达式语法是什么。幸运的是,您可以将 perl 语法与 grep 一起使用,因此 grep -P 可以工作,但与 egrep 相同的 grep -E 将无法工作(它会很贪心)。

另请参阅:http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html

【讨论】:

grep -P 在 GNU grep 2.9 中不起作用——刚刚尝试过(它没有错误,只是默默地不应用 ?。有趣的是 not 类 i> 例如:env|grep '[^\=]*\=' 在 Darwin/OS X 10.8 Mountain Lion 中没有 grep -P 选项或 pgrep 命令,但 egrep 效果很好。 我的 OS X 10.9 机器上有一个 pgrep 命令,但它是一个完全不同的程序,其目的是“按名称查找或通知进程”。 @robertotomás 在这里回复一个 6 年前的评论,但是....我也这么想,然后意识到我得到了多个非贪婪匹配。例如,在彩色终端上,您可以看到 ` echo "bbbbb" | grep -P 'b.*?b'` 返回 2 个匹配项。【参考方案3】:

我的 grep 在尝试了此线程中的内容后有效:

echo "hi how are you " | grep -shoP ".*? "

只需确保在每一行都附加一个空格

(我的是逐行搜索吐词)

【讨论】:

-shoP 很好的助记符 :) echo "bbbbb" | grep -shoP 'b.*?b' 有点学习经验。就明确的懒惰而言,唯一对我有用的东西。【参考方案4】:

grep

对于grep 中的非贪婪匹配,您可以使用否定字符类。换句话说,尽量避免使用通配符。

例如,要从页面内容中获取所有指向 jpeg 文件的链接,您可以使用:

grep -o '"[^" ]\+.jpg"'

要处理多行,首先通过xargs 管道输入。为提高性能,请使用ripgrep

【讨论】:

从来没有想过这样使用它。为我工作。【参考方案5】:

对不起,我迟到了 9 年,但这可能对 2020 年的观众有用。

所以假设你有一个像"Hello my name is Jello" 这样的行。 现在,您要查找以'H' 开头并以'o' 结尾的单词,中间包含任意数量的字符。我们不想要线条,我们只想要文字。因此,我们可以使用以下表达式:

grep "H[^ ]*o" file

这将返回所有单词。它的工作原理是:它将允许所有字符而不是空格字符,这样我们可以避免在同一行中出现多个单词。

现在您可以将空格字符替换为您想要的任何其他字符。 假设最初的行是"Hello-my-name-is-Jello",那么你可以使用表达式获取单词:

grep "H[^-]*o" file

【讨论】:

【参考方案6】:

简短的回答是使用下一个正则表达式:

(?s)<car .*? model=BMW .*?>.*?</car>
(?s) - 这使得多行匹配 .*? - 以懒惰的方式匹配任何字符,多次(最小 匹配)

一个(稍微)更复杂的答案是:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

这将使得在以下文本中匹配 car1 和 car2 成为可能

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
(..) 表示捕获组 \1 在此上下文中匹配与最近匹配的相同文本 捕获组号 1

【讨论】:

【参考方案7】:

我知道这有点过时了,但我只是注意到这行得通。它从我的输出中删除了清理和清理。

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20

【讨论】:

以上是关于如何在 grep 中进行非贪婪匹配?的主要内容,如果未能解决你的问题,请参考以下文章

简单聊一聊正则表达式中的贪婪匹配和非贪婪匹配

15.python正则匹配 元字符转义重复或捕获分组断言:零度断言负向零宽断言贪婪非贪婪引擎选项

re模块中的非贪婪匹配

正则表达式贪婪与非贪婪比较

Python3中正则的贪婪匹配模式

python基础:re模块匹配时贪婪和非贪婪模式