【问题标题】:How to get text which is middle of Tags?如何获取标签中间的文本?
【发布时间】:2014-03-23 00:47:15
【问题描述】:
      <li><b> Some Text:</b></li><li><b> Some Text:</b></li>
      <pg>something else</pg> <li><b> Some Text:</b> </li>
      <li><b> Some Text:</b></li>
      <li><b> Some Text:</b> More Text </li> <li><b> Some Text:</b> More Text </li>

如果这是我的输入字符串和

      Some Text:
      Some Text:
      Some Text:
      Some Text: More Text 
      Some Text: More Text

这是我的输出但我得到的只是

      Some Text:
      Some Text:
      Some Text: More Text

这是我在linux中的shell脚本函数

     #!/bin/sh
     sed -n -e 's/.*<li>\(.*\)<\/li>.*/\1/p' $1 > temp
     sed -e 's/<[<\/b]*>//g' temp >out

请给我一些想法,哪里出错了。

【问题讨论】:

  • 不要用sedawk解析HTML; sed 设计用于基于行的编辑,awk 用于基于字段的任务。两者都不适合元素可能跨越多行的一般结构化文本。

标签: bash sed


【解决方案1】:

这是GNU awk 的一种方式(第一行是空行):

$ gawk '
RT=="</b>"||RT=="</li>" && NF {
    gsub(/^ *| *$/,"")
    printf "%s%s",(ORS=!(NR%2)?"":"\n"),$0
}
END { print "\n" }' RS='</?b>|</?li>' file

Some Text:
Some Text:
Some Text:
Some Text:
Some Text:More Text
Some Text:More Text

【讨论】:

  • 非常感谢您的帮助。但是无论如何我都使用 awk 和 sed 来执行此操作,因为我对 shell 脚本非常陌生
  • @user1574779 您使用的是什么操作系统?您的awk 很可能指向gawk
  • Linux Mint 我尝试了解 awk 的功能。无论如何谢谢
  • @user1574779 如果您指的是 Linux Mint,请使用 awk 运行确切的命令。
【解决方案2】:

如果您不介意使用第三方工具 - 多平台网络抓取实用程序xidel - 它变得如此简单: p>

xidel file.html -e '/li'

这会提取所有(顶级)li 元素的纯文本内容,并将每个元素打印在单独的行上以生成所需的输出。

【讨论】:

    【解决方案3】:

    首先要做的事情:一般来说,使用理解 HTML 的工具(请参阅我的其他答案)而不是 awksed 进行 HTML 解析 - 正如 @chepner 简洁地说的那样:

    不要使用 sed 或 awk 解析 HTML; sed 是为基于行的编辑而设计的,而 awk 是为基于字段的任务而设计的。两者都不适用于元素可能跨越多行的一般结构化文本。

    因此,以下解决方案在有限的情况下工作,但不能很好地概括。


    @jaypal 已经提供了一个 GNU awk (gawk) 特定的答案。
    这应该适用于所有接受正则表达式作为输入记录分隔符 (RS)awk 风格(例如gawkmawknawk):

    awk -v RS='</?li>\n*' '
     /^<b>/ { t=$0; gsub(/<\/?b>/, "", t); gsub(/^ +| +$/, "", t); print t}
    ' file
    

    较旧且符合 POSIX 的 awk 风格 - 例如 OSX 中基于 BSD 的风格 - 仅接受单个文字字符。作为RS,所以上面的行不通;在 OSX 上,以下sed 命令实现了相同的效果(也适用于 Linux):

     sed -E 's/<\/?li>/\'$'\n''/g' file | 
      sed -En '/^<pg>/! { /[^ ]/ { s/<\/?b>//g; s/^ +| +$//gp; }; }'
    

    这两种解决方案都会从输出行中删除前导和尾随空格。

    【讨论】:

      【解决方案4】:
      #!/bin/sh
      

      您的第一个 sed 行不是您想要的: 每行只匹配一次

      sed -n -e 's/.*<li>\(.*\)<\/li>.*/\1/p' $1 > temp
      this...........................^^
      

      匹配....该行的其余部分(显然不是您所期望的)

      一种快速的解决方法是在任何其他处理之前将每个&lt;/li&gt; 更改为&lt;/li&gt; plus linefeed

      #!/bin/sh
      
      sed -e 's/<\/li>/<\/li>\n/g' "$1" |\
      sed -n -e 's/.*<li>\(.*\)<\/li>/\1/p' |\
      sed -e 's/<[\/b]*>//g' >out
      

      我不是 sed 专家...其他人可能有更优雅的解决方案

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多