【问题标题】:How can I retrieve a collection of values from nested HTML-like elements using RegExp?如何使用 RegExp 从嵌套的类似 HTML 的元素中检索值的集合?
【发布时间】:2008-12-04 13:15:58
【问题描述】:

我在为以下任务创建正则表达式时遇到问题:

假设我们有类似 HTML 的文本:

<x>...<y>a</y>...<y>b</y>...</x>

我想获取位于给定&lt;x&gt; 标记内的&lt;y&gt;&lt;/y&gt; 标记内的值集合,因此上述示例的结果将是两个元素["a","b"] 的集合。

此外,我们知道:

  • &lt;y&gt;标签不能包含在其他&lt;y&gt;标签中
  • ... 可以包含任何文本或其他标签。

如何使用 RegExp 实现这一点?

【问题讨论】:

    标签: html regex parsing


    【解决方案1】:

    这是HTML/XML parser 的工作。你可以用正则表达式来做,但是会很麻烦。我链接的页面中有示例。

    【讨论】:

    • 很遗憾,不能保证文本是有效的 XML 格式,也不是 HTML 格式
    • 好吧,假设它是 HTML,标准答案是通过 Tidy 运行它。使用 --clean,Tidy 只输出应该可以被几乎任何 HTML/XML 包解析的有效 XHTML。
    • +1 这个 - 为什么现在每个人都想用正则表达式解析 XML?
    • 首先,正如我所说 - 这不是 XML。其次,我不想参与使用任何工具处理此文本以将其转换为良好的 HTML/XML,只是为了能够使用标准 HTML/XML 库对其进行解析。这是开销。我所说的文字小而简单。 RegEx 正是这里匹配的内容。
    • 当您有无限数量的潜在匹配时,处理和解析将比正则表达式简单得多。在为自己制造更多问题之前,请先试用专为解决此问题而设计的工具。
    【解决方案2】:

    我相信你的话:

    "y" tags cannot be enclosed in other "y" tags
    
    input looks like: <x>...<y>a</y>...<y>b</y>...</x>
    

    以及其他所有内容也嵌套且格式正确的事实。 (免责声明:如果不是,那不是我的错。)

    首先,找到任何 X 标记的内容,并在此匹配项上循环:

    <x[^>]*>(.*?)</x>
    

    然后(在循环体中)从上面的“外部”匹配项的匹配组 1 中找到任何 Y 标记:

    <y[^>]*>(.*?)</y>
    

    伪代码:

    input = "<x>...<y>a</y>...<y>b</y>...</x>"
    x_re  = "<x[^>]*>(.*?)</x>"
    y_re  = "<y[^>]*>(.*?)</y>"
    
    for each x_match in input.match_all(x_re)
      for each y_match in x_match.group(1).value.match_all(y_re)
        print y_match.group(1).value
      next y_match
    next x_match
    

    伪输出:

    a
    b
    

    cmets 的进一步说明表明,在任何 X 元素中都存在任意数量的 Y 元素。这意味着没有一个正则表达式可以匹配它们并且提取它们的内容。

    【讨论】:

    • 谢谢。从一开始就没有提到它,但我确实了解如何使用循环来实现目标。但我 100% 确定有一个使用单一“匹配”操作的解决方案——这就是我想要弄清楚的 :)
    • 如果 Y 元素的数量没有硬性限制,那么就没有正则表达式唯一的解决方案。是什么让你如此确定存在?也许这个问题缺少更多细节。
    • 正如我所说,您的问题缺少有关您希望处理的字符串的确切结构的一些细节。
    • “y”标签的数量没有限制(因此结果集合大小没有限制)。您认为我还需要提供哪些其他详细信息?
    • 嵌套或不嵌套,元素可以有或没有属性,是机器生成的还是用户输入的,最后但同样重要的是:你真的想做什么?也许有比正则表达式更好的方法可以让你到达那里。
    【解决方案3】:

    简短:使用 XPath :)

    【讨论】:

    • 他在对@Bill the Lizard 的评论中说“文本不能保证是有效的 XML”
    【解决方案4】:

    如果我们知道您使用的语言或工具会有所帮助;在语法、语义和功能上有很多变化。这是用 Java 实现的一种方法:

    String str = "<y>c</y>...<x>...<y>a</y>...<y>b</y>...</x>...<y>d</y>";
    String regex = "<y[^>]*+>(?=(?:[^<]++|<(?!/?+x\\b))*+</x>)(.*?)</y>";
    Matcher m = Pattern.compile(regex).matcher(str);
    while (m.find())
    {
      System.out.println(m.group(1));
    }
    

    一旦我匹配了&lt;y&gt;,我使用前瞻来确认前面某处有&lt;/x&gt;,但在当前位置和它之间没有&lt;x&gt;。假设伪 HTML 格式合理,这意味着当前匹配位置在 "x" 元素内。

    我大量使用所有格量词,因为它们让这样的事情变得更容易,但正如你所见,正则表达式仍然有点像怪物。除了 Java,我所知道的支持所有格量​​词的唯一正则表达式风格是 PHP 和 JGS 工具(RegexBuddy/PowerGrep/EditPad Pro)。另一方面,许多语言都提供了一次获取所有匹配项的方法,但在 Java 中,我必须为此编写自己的循环代码。

    因此,可以用一个正则表达式完成这项工作,但这是一个非常复杂的工作,并且正则表达式和封闭代码都必须根据您正在使用的语言进行定制。

    【讨论】:

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