【问题标题】:Not able to extract with grep无法用 grep 提取
【发布时间】:2017-03-05 03:16:31
【问题描述】:
> <img alt="Citizen Kane Poster" title="Citizen Kane Poster"
src="https://images-na.ssl-images-amazon.com/images/M/MV5BMTQ2Mjc1MDQwMl5BMl5BanBnXkFtZTcwNzUyOTUyMg@@._V1_UX182_CR0,0,182,268_AL_.jpg"
itemprop="image" />

我想从上面的文字中提取海报的网址。 这是我的 grep 语句:

count=$(grep -zPo '(?<=> <img alt=").*?src="\K.*?(?="itemprop="image")'  ~/movie_local)

movie_local 是我保存网站页面源代码的地方。 我正在学习 grep 并且没有完整的命令,所以请对我温柔一点。你能帮帮我吗? :)

【问题讨论】:

  • 首先,don't use regex to parse HTML。不过,您正在寻找的是 capturing group
  • 捕获组是一种提取部分匹配项的方法。我不熟悉如何在 grep 中使用它们,因为命令行有点奇怪。不过,第二个链接似乎很好地解释了它。
  • 我建议使用 XML/HTML 解析器 (xmllint, xmlstarlet ...)。
  • @3ocene: grep 实现(至少我不知道)不支持捕获组:虽然您可以将(...) 用于分组,但您赢了'无法访问那些组捕获的内容。但是,将-o 选项(仅返回(整个)捕获的部分)与环视断言(需要 GNU grep-P)组合是真正捕获组支持的(有限)替代品。这正是这个问题的命令所尝试的,但失败了(出于不同的原因)。
  • 其实我在测试后添加了\s*“手动”。它不适用于 * 量词。无论如何,是的,这只是一个提示,而不是试图回答。

标签: regex bash grep


【解决方案1】:

(正如之前多次说过的,最好的解决方案是使用 HTML 解析器。)

使用 GNU grep,试试这个简化版:

grep -zPo '<img alt=[^/]+?src="\K[^"]+' ~/movie_local

您最初尝试的固定版本(注意 (?s) 前缀;请参阅下面的说明):

grep -zPo '(?s)> <img alt=".*?src="\K.*?(?=")' ~/movie_local

替代方案,[\s\S] 使用 ad-hoc 来匹配 any 字符,包括 \n

grep -zPo '> <img alt="[\s\S]*?src="\K.*?(?=")' ~/movie_local

至于为什么你的尝试没有成功

  • 当您使用 -P(用于支持 PCRE (Perl-Compatible Regular Expression)时,. 匹配 \n 字符。 默认情况下,因此即使您使用 -z 一次读取整个输入,.* 也不会跨行边界匹配。你有两个选择:

    • 在正则表达式的开头设置option s ("dotall") - (?s) - 这使得. 匹配任何 字符,包括\n
    • 临时解决方法:使用[\s\S] 而不是.
  • 顺便说一句:\K 构造在语法上更简单,有时更灵活替代回溯断言 ((?&lt;=...) .

    • 你的命令有both,在这种情况下这并没有什么坏处,但没有必要。
    • 相比之下,您是否尝试过 (?&lt;=&gt;\s*&lt;img alt=") 以获得更灵活的空白匹配 - 请注意 \s* 代替原来的单个空格 - 您的后向断言会失败,因为后向断言必须是固定长度(至少从 GNU grep v2.26 开始)。
      但是,仅使用 \K 会起作用:&gt;\s*&lt;img alt=")\K
      \K 只是删除所有匹配的到目前为止(不包括在输出中)。

【讨论】:

    猜你喜欢
    • 2020-02-27
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 2021-03-11
    • 2013-09-09
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多