【问题标题】:How can I use a sed regex to extract HTML and modify a timestamp?如何使用 sed 正则表达式提取 HTML 并修改时间戳?
【发布时间】:2016-01-02 16:22:18
【问题描述】:

使用 curl + grep 我得到以下输出:

<h3>Serial ID: L322607B2411012</h3>
<span>felipea</span>
<span>2015-10-05 20:06:43 UTC</span>

我是 sed-stuff 的新手,我想使用 sed 来获得以下输出:

L322607B2411012
felipea
20:06:43

为了得到结果,我编写了以下正则表达式:

/<|>|h3|/|span| UTC|.......... /g

http://www.regexr.com/ 上测试,文字:

<h3>Serial ID: L322607B2411012</h3>
<span>felipea</span>
<span>2015-10-05 20:06:43 UTC</span>
<h3>Serial ID: L322607B2411135</h3>
<span>tressino</span>
<span>2015-10-05 19:57:10 UTC</span>

它会根据需要突出显示匹配项(图片:http://snag.gy/0ge60.jpg),但是当我进行真正的测试时它不起作用,请按照命令:

curl internalURL | egrep -i '(utc|Serial ID:|tressino|felipea)' | sed 's/<|>|h3|/|span| UTC|.......... /g'

上面的命令返回正常的输出,和没有sed+regex一样。

转义斜线会返回以下错误:

sed 's/<|>|h3|\/|span| UTC|.......... /g'
sed: -e expression #1, char 35: unterminated `s' command

谁能指出我做错了什么?

提前致谢。

【问题讨论】:

  • 怎么不行?会发生什么?
  • 您需要转义斜线:\/。否则模式会提前结束。
  • 什么都不做,输出和没有sed+regex完全一样。如果我使用 sed -r 而不是 sed 它会返回以下输出:|span| UTC|........ |跨度| UTC|........ |跨度| UTC|........ S|跨度| UTC|........ e|跨度| UTC|........ r|span| UTC|........ i|跨度| UTC|........一个|跨度| UTC|........ l|跨度| UTC|........ |跨度| UTC|........ I|跨度| UTC|........ D|跨度| UTC|........ :|跨度| UTC|........ |跨度| UTC|........ L|跨度| UTC|........等等
  • 转义斜线,因为@lenz 说它返回以下错误: sed 's/|h3|\/|span| UTC|........ /g' sed: -e 表达式 #1, char 35: 未终止的 `s' 命令
  • 哦,这是你真正的正则表达式,而不仅仅是某种缩写符号?

标签: html regex sed


【解决方案1】:

TL;博士

不要使用正则表达式解析 HTML。使用支持 XPath 的工具,例如XmlStarlet

使用 XmlStarlet 的示例

给定格式良好的输入,例如:

<html>
  <body>
    <h3>Serial ID: L322607B2411012</h3>
    <span>felipea</span>
    <span>2015-10-05 20:06:43 UTC</span>
    <h3>Serial ID: L322607B2411135</h3>
    <span>tressino</span>
    <span>2015-10-05 19:57:10 UTC</span>
  </body>
</html>

您可以使用 XPath 提取所需的文本节点。例如:

$ xmlstarlet sel -t -v '//h3/text() | //span/text()' -n /tmp/foo.html
Serial ID: L322607B2411012
felipea
2015-10-05 20:06:43 UTC
Serial ID: L322607B2411135
tressino
2015-10-05 19:57:10 UTC

然后,您可以使用 sed 或 awk 调整时间戳并将输出分解为记录。例如,考虑这个单行:

$ xmlstarlet sel -t -v '//h3/text() | //span/text()' -n /tmp/foo.html |
    awk '/UTC$/ {print $2 "\n"; next}; {print}'
Serial ID: L322607B2411012
felipea
20:06:43

Serial ID: L322607B2411135
tressino
19:57:10

【讨论】:

    【解决方案2】:

    更改正则表达式如下:

    sed 's/<|>|h3|\/|span| UTC//g'
    

    替换命令是s/.../.../,其中第一个省略号 (...) 是模式,第二个是替换。

    编辑:正如您实际上在问出了什么问题,这里有一个解释:在正则表达式替换s/&lt;|&gt;|h3|/|span| UTC|.......... /g 中,模式是&lt;|&gt;|h3|,即。 &lt;&gt;h3 或什么都没有。替换为|span| UTC|..........,这就是您使用-r 选项得到的结果。

    【讨论】:

    • 完美。我刚刚添加了它需要删除的其余字符串并且它起作用了: sed -r 's/|h3|\/|span|ID: | UTC|........ //g'
    • @anubhava:是的,但是点也删除了这个输出:)
    • 哇,这是删除不需要的字符串的方法。你知道...... 可以在正则表达式中删除什么吗?
    • @anubhava:据我了解,它将匹配任何具有相同点长的字符串,在这种情况下(.......... )它将匹配 10 个连续字符,末尾有一个空格在它替换正则表达式具有的所有其他模式之后。不知道能不能解释清楚...
    • @ZeroNegative 你解释得很好。问题是,如果你不知道 curl 会给你什么作为输入,它可能会匹配它不应该匹配的东西。
    【解决方案3】:

    您最好使用这个简单的awk 命令将您的文本放在h3span 标签之间:

    awk -F '</?(span|h3)>' '{print $2}' file
    Serial ID: L322607B2411012
    felipea
    2015-10-05 20:06:43 UTC
    Serial ID: L322607B2411135
    tressino
    2015-10-05 19:57:10 UTC
    

    PS:管道到另一个以获得您想要的输出:

    awk -F '</?(span|h3)>' '{print $2}' file | awk '/ID:/{print $3;next} / UTC/{print $2;next} 1'
    L322607B2411012
    felipea
    20:06:43
    L322607B2411135
    tressino
    19:57:10
    

    但请记住,awk/sed/grep 等并不是解析 HTML 文本的最佳工具。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-16
      • 2015-12-15
      • 2013-06-03
      • 1970-01-01
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多