【问题标题】:Awk multiline non-greedy matching workaroundawk 多行非贪婪匹配解决方法
【发布时间】:2021-07-25 03:13:10
【问题描述】:

我正在尝试使用 awk 提取 HTML 列表的内容。 一些列表条目是多行的。

示例输入列表:

<ul>
    <li>
        <b>2021-07-21:</b> Lorem ipsum 
    </li>
    <li>
        <b>2021-07-19:</b> Lorem ipsum 
    </li>
    <li><b>2021-07-10:</b> Lorem ipsum</li>
</ul>

我正在使用的命令:

awk -v RS="" '{match($0, /<li>(.+)<\/li>/, entry); print entry[1]}' file.html

当前输出:

        <b>2021-07-21:</b> Lorem ipsum 
    </li>
    <li>
        <b>2021-07-19:</b> Lorem ipsum 
    </li>
    <li><b>2021-07-10:</b> Lorem ipsum

期望的输出:

        <b>2021-07-21:</b> Lorem ipsum 
        <b>2021-07-19:</b> Lorem ipsum 
    <b>2021-07-10:</b> Lorem ipsum

我知道问题是因为列表条目没有用空行分隔。 我想过使用非贪婪匹配,但显然 Awk 不支持它。 有没有可能的解决方法?

【问题讨论】:

  • Don't Parse XML/HTML With Regex. 我建议使用 XML/HTML 解析器 (xmlstarlet, xmllint ...)。
  • @Cyrus 这是一个巨大的 awk 的一小部分。添加依赖项是不可取的。

标签: html awk


【解决方案1】:

使用 GNU awk 表示多字符 RS,\s 简写为 [[:space:]]

$ awk -v RS='\\s*</?li>\\s*' '!(NR%2)' file
<b>2021-07-21:</b> Lorem ipsum
<b>2021-07-19:</b> Lorem ipsum
<b>2021-07-10:</b> Lorem ipsum

我假设您不是真的想要问题中预期输出中显示的前导空格,或者您不在乎它是否存在。

【讨论】:

    【解决方案2】:

    使用您展示的示例,请尝试遵循awk 代码。用 GNU awk 编写和测试。

    awk -v RS='</li>' '
    match($0,/<li>.*/){
      val=substr($0,RSTART,RLENGTH)
      gsub(/<li>\n*[[:space:]]*|\n*[[:space:]]*$/,"",val)
      print val
    }
    ' Input_file
    

    说明:为上述添加详细说明。

    awk -v RS='</li>' '              ##Starting awk program from here and setting RS as </li> here.
    match($0,/<li>.*/){              ##Matching <li> till end of line here.
      val=substr($0,RSTART,RLENGTH)  ##Creating val which has matched regex value here.
      gsub(/<li>\n*[[:space:]]*|\n*[[:space:]]*$/,"",val)  ##Globally substituting <li> followed by 0 or more new lines followed by 0 or more spaces OR substituting ending new lines or spaces with NULL in val.
      print val                      ##Printing val here.
    }
    ' Input_file                     ##Mentioning Input_file name here.
    

    【讨论】:

      【解决方案3】:

      这里有一个 Perl:

      perl -0777 -nE 'say $1  while(/<li>\s*([\s\S]*?)\s*<\/li>/g)' file
      <b>2021-07-21:</b> Lorem ipsum
      <b>2021-07-19:</b> Lorem ipsum
      <b>2021-07-10:</b> Lorem ipsum
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-02
        • 2011-08-29
        • 2017-10-16
        • 1970-01-01
        • 2015-02-11
        • 1970-01-01
        • 1970-01-01
        • 2017-05-07
        相关资源
        最近更新 更多