AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 441927
Accepted
C0deDaedalus
C0deDaedalus
Asked: 2018-05-05 22:50:54 +0800 CST2018-05-05 22:50:54 +0800 CST 2018-05-05 22:50:54 +0800 CST

如何或为什么使用 `.*?` 比 `.*` 更好?

  • 772

我在 SuperUser 上回答了这个问题,该问题与 grepping 输出时使用的正则表达式类型有关。

我给出的答案是这样的:

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

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

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

那么这个,

the?是 上的修饰符*,使其变得懒惰而不是贪婪的默认值。假设 PCRE。

我用谷歌搜索PCRE,但在我的答案中无法理解这有什么意义?

最后这个,

我还应该指出,这是正则表达式(grep 默认执行 POSIX 正则表达式),而不是 shell glob。

我只知道 Regex 是什么以及它在 grep 命令中的基本用法。所以,我无法得到这 3 条评论中的任何一条,我有这些问题:

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

也有助于理解评论,如果有人可以


更新:作为问题的答案Regex 与 Shell Globs 有何不同? @Kusalananda在他的评论中提供了这个链接。

注意:如果需要,请在回答参考上下文之前阅读我对此问题的回答。

regular-expression wildcards
  • 3 3 个回答
  • 2955 Views

3 个回答

  • Voted
  1. Ashok Arora
    2018-05-06T01:03:36+08:002018-05-06T01:03:36+08:00

    假设我采用如下字符串:

    can cats eat plants?

    使用贪心c.*s将匹配整个字符串,因为它以 开头c和结尾s,作为一个贪心运算符,它会继续匹配直到最后出现 s。

    而使用惰性c.*?s只会匹配直到s找到第一次出现,即 string can cats。

    从上面的示例中,您可能能够收集到:

    “贪婪”意味着匹配最长的可能字符串。“懒惰”意味着匹配最短的可能字符串。将 a 添加到, ,或?等量词后使其变得懒惰。*+?{n,m}

    • 10
  2. Best Answer
    nxnev
    2018-05-06T07:32:34+08:002018-05-06T07:32:34+08:00

    Ashok 已经指出了和 之间的区别.*,.*?所以我将提供一些额外的信息。

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

    • 固定字符串,带有-F选项
    • 基本正则表达式 (BRE),默认
    • 扩展正则表达式 (ERE),带有-E选项
    • Perl 兼容的正则表达式 (PCRE),带有-PGNU grep 中的选项

    grep默认使用 BRE。

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

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

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

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

    # 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
    

    你能解释一下.*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>
    

    1.正如 Kusalananda 指出的那样,正则表达式上下文中“最长”和“最短”的含义有点棘手。有关详细信息,请参阅官方文档。
    2.不建议用正则解析html。这只是一个用于教育目的的示例,请勿在生产中使用它。

    • 9
  3. user232326
    2018-05-06T19:02:21+08:002018-05-06T19:02:21+08:00

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

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

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

    2. 作为一个整体:

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

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

      glob中的星号表示与正则表达式中的星号不同的含义:

      glob* matches any number (including none) of任何字符。
      正则表达式* matches any number (including none) of the前面的元素。

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

      sedecho "$var" | sed 's/W.*d//' #打印:你好!
      grepgrep -o 'W.*d' <<<"$var" #打印世界!

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

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

      bash[[ "$var" =~ (H.*l) ]] # match: Hello Worl
      sedecho "$var" | sed -E 's/(d|o)//g' # print: Hell Wrl!
      awkawk '/W.*d/{print $1}' <<<"$var" # print: Hello
      grepgrep -oE 'H.*l' <<<"$var" # print: Hello Worl

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

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

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

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

    这只是冰山一角,有贪婪的,有懒惰的,也有温顺的或占有欲的。还有lookahead 和lookbehind但这些不适用于星号*。

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

    $ 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 评论。释义:

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

    问题

    • 的用法有什么区别。? 与.. ?

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

    • 1

相关问题

  • 为什么正则表达式与 sed 命令的输入不匹配 [重复]

  • globstar 什么时候进入符号链接目录?

  • 使用特殊字符转换密码以与期望脚本一起使用

  • 更少:使用 AND 的多个过滤条件

  • mv *.cache.{js,woff} sub_folder - 作为 shell 命令工作,但不在 Makefile 内

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve