为什么或为什么使用`。*?`比`。*`更好?


9

在SuperUser上回答了这个问题,该问题与在提取输出时使用的某种正则表达式有关。

我给出的答案是这样的:

 tail -f log | grep "some_string.*some_string"

然后,在对我的答案的三条评论中,@ Bob写道:

.*贪婪,可能会捕获比您想要的更多的东西。.*?通常更好。

然后这个

?上一个修改*,使其成为懒惰,而不是贪婪的默认。假设PCRE。

我用google搜索PCRE,但无法在我的答案中得到什么意义?

最后,

我还应该指出,这是regex(默认情况下,grep执行POSIX regex),而不是shell glob。

我只知道什么是正则表达式以及它在grep命令中的基本用法。因此,我无法获得这3条评论中的任何一条,并且我想到了以下这些问题:

  • .*?vs. 用法有什么区别.*
  • 哪个更好,在什么情况下?请提供示例。

另外,如果有人可以理解这些意见,将会很有帮助。


更新:作为对问题的回答,正则表达式与Shell Globs有何不同? @Kusalananda在他的评论中提供了此链接

注意:如果需要,请在回答引用上下文之前阅读我对这个问题的回答。


这是两个非常不同的问题。第一个问题由unix.stackexchange.com/questions/57957/…回答,而第二个问题取决于模式的应用(不能在所有情况下都说“更好”)。
库萨兰达

您可以将此问题仅编辑.*.*?问题相关。该站点上已经解决了“正则表达式和shell球之间的差异”问题。
库萨兰达

Answers:


7

阿肖克已经指出的区别.*.*?,所以我就提供一些额外的信息。

grep (假设是GNU版本)支持4种匹配字符串的方法:

  • 固定弦
  • 基本正则表达式(BRE)
  • 扩展正则表达式(ERE)
  • Perl兼容的正则表达式(PCRE)

grep 默认情况下使用BRE。

BRE和ERE记录在POSIX 的“ 正则表达式”一章中,PCRE记录在其官方网站上。请注意,功能和语法可能因实现而异。

值得一提的是,BRE和ERE都不支持惰性

多个相邻重复符号(“ +”,“ *”,“?”和间隔)的行为会产生不确定的结果。

因此,如果要使用该功能,则需要使用PCRE:

# BRE greedy
$ grep -o 'c.*s' <<< 'can cats eat plants?'
can cats eat plants

# BRE lazy
$ grep -o 'c.*\?s' <<< 'can cats eat plants?'
can cats eat plants

# ERE greedy
$ grep -E -o 'c.*s' <<< 'can cats eat plants?'
can cats eat plants

# ERE lazy
$ grep -E -o 'c.*?s' <<< 'can cats eat plants?'
can cats eat plants

# PCRE greedy
$ grep -P -o 'c.*s' <<< 'can cats eat plants?'
can cats eat plants

# PCRE lazy
$ grep -P -o 'c.*?s' <<< 'can cats eat plants?'
can cats

编辑1

你能解释一下.*vs .*?吗?

  • .*用于匹配可能的“最长” 1模式。

  • .*?用于匹配“最短” 1模式。

以我的经验,最想要的行为通常是第二个。

例如,假设我们有以下字符串,而我们只想匹配html标签2,而不是它们之间的内容:

<title>My webpage title</title>

现在比较.*vs .*?

# Greedy
$ grep -P -o '<.*>' <<< '<title>My webpage title</title>'
<title>My webpage title</title>

# Lazy
$ grep -P -o '<.*?>' <<< '<title>My webpage title</title>'
<title>
</title>

正如Kusalananda指出的那样 ,在正则表达式中“最长”和“最短”的含义有些棘手。有关更多信息,请参考官方文档。
2. 不建议使用regex解析html。这只是出于教育目的的示例,请勿在生产中使用。


你能解释一下.*vs .*?吗?
C0deDaedalus

@ C0deDaedalus更新。
nxnev

9

假设我采用类似以下的字符串:

can cats eat plants?

使用greedy c.*s将匹配整个字符串,因为它以c和开头s,作为greedy运算符,它将继续匹配直到最终出现s为止。

而使用lazy c.*?s只会匹配到s找到第一个匹配项,即string can cats

从上面的示例中,您可以收集到以下信息:

“ Greedy”表示匹配最长的字符串。“惰性”表示匹配最短的字符串。添加?到像一个量词*+?,或{n,m}使其懒惰。


1
“最短的可能”将是cats,因此严格意义上讲并不是强制执行“最短的可能”。
库萨兰达

2
@Kusalananda是正确的,严格意义上并不是严格意义上的,而是“尽可能短的”,这里表示在c和s的第一次出现之间。
Ashok '18年

1

字符串可以通过几种方式进行匹配(从简单到更复杂):

  1. 作为静态字符串(假设var ='Hello World!'):

    [ "$var" = "Hello World!" ] && echo yes
    echo "$var" | grep -F "Hello"
    grep -F "Hello" <<<"$var"

  2. 作为一个整体:

    echo ./* #列出pwd 中的所有文件。
    case $var in (*Worl*) echo yes;; (*) echo no;; esac
    [[ "$var" == *"Worl"* ]] && echo yes

    有基本的和扩展的球形。该case示例使用基本的glob。bash [[示例使用扩展的glob。第一个文件匹配可以是基本的,也可以在某些shell上扩展,例如extglob在bash中设置。在这种情况下,两者是相同的。Grep无法使用Glob。

    全局星号表示与正则表达式中的星号不同:

    * matches any number (including none) of任何字符
    * matches any number (including none) of the元素之前

  3. 作为基本的正则表达式(BRE):

    echo "$var" | sed 's/W.*d//' #打印:您好!
    grep -o 'W.*d' <<<"$var" #打印世界!

    (基本)shell或awk中没有BRE。

  4. 扩展正则表达式(ERE):

    [[ "$var" =~ (H.*l) ]] #匹配:Hello Worl
    echo "$var" | sed -E 's/(d|o)//g' #打印:Hell Wrl!
    awk '/W.*d/{print $1}' <<<"$var" #打印:Hello
    grep -oE 'H.*l' <<<"$var" #打印:Hello Worl

  5. Perl兼容的正则表达式:

    grep -oP 'H.*?l #打印:Hel

仅在PCRE中,a才*?具有某些特定的语法含义。
它使星号变得懒惰(懒惰):懒惰而不是贪婪

$ grep -oP 'e.*l' <<<"$var"
ello Worl

$ grep -oP 'e.*?l' <<<"$var"
el

这只是冰山一角,有贪婪的,懒惰的温顺的或占有欲的。也有向前看和向后看,但不适用于星号*

还有一种替代方法可以达到与非贪婪正则表达式相同的效果:

$ grep -o 'e[^o]*o' <<<"$var"
ello

这个想法很简单:不要使用点.,否定下一个要匹配的字符[^o]。带有网页标签:

$ grep -o '<[^>]*>' <<<'<script type="text/javascript">document.write(5 + 6);</script>'
<script type="text/javascript">
</script>

以上应该完全阐明所有@Bob 3注释。释义:

  • 。*是常见的正则表达式,而不是glob。
  • 只有正则表达式可以与PCRE兼容。
  • 在PCRE中:修改*量词。.*是贪婪.*?不是。

问题

  • 的用法有何区别??与。

    • A .*?仅在PCRE语法中有效。
    • A .*更便于携带。
    • 通过将点替换为负字符范围,可以实现与非贪婪匹配相同的效果: [^a]*
  • 哪个更好,在什么情况下?请提供示例。
    更好?这取决于目标。没有更好,每种都有不同的用途。我在上面提供了几个示例。需要更多吗?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.