【问题标题】:Using multiple regexes to capture matching nested xml tags使用多个正则表达式捕获匹配的嵌套 xml 标签
【发布时间】:2014-06-27 08:20:47
【问题描述】:

假设我有一个 xml 文件,其中包含嵌套在自身内部的标签,例如

<TAG>one<TAG>two</TAG>one</TAG>

来自this page,我有两个正则表达式示例与此字符串不匹配,例如,您会得到

<TAG>one<TAG>two</TAG>

这是不平衡的。根据 Google 的说法,无法找到能够正确解析 html 的正则表达式,例如 herehere

正则表达式无法进行整个 HTML 解析,因为它依赖于匹配开始和结束标记,而这在正则表达式中是不可能的。

正则表达式只能匹配正则语言,但 HTML 是一种上下文无关语言。在 HTML 上使用正则表达式唯一可以做的就是启发式方法,但这并不适用于所有条件。应该有可能呈现一个将被任何正则表达式错误匹配的 HTML 文件。

这是一个很好的清晰的理论答案,但它让我思考:是否可以通过编程方式使用多个正则表达式和/或循环?

【问题讨论】:

  • 当然可以,但你可能会伤到自己。我根据你的例子制作了some progress here。它一次搜索最深的元素,您只需将其废弃,留下标识符,然后再次尝试捕获。
  • 这是出于好奇,还是因为您想用它来解决问题?因为如果是后者,那么有几个 XML 解析器使用起来非常简单。
  • 什么是样本输入和样本输出,请清楚
  • 如果您阅读了该答案,请考虑阅读 cmets:stackoverflow.com/questions/590747/…
  • @MikeH-R:真的只是出于好奇。我使用 c# xml 类来做我想做的事情。

标签: xml regex


【解决方案1】:

正则表达式不是正则的。许多主要的正则表达式风格都允许您匹配各种递归结构。

因此,为了匹配您在 PCRE 中的示例,您可以编写 (demo):

<TAG>(?:[^<>]+|(?R))*</TAG>

无需任何额外的代码或正则表达式。这不是 XML 解析器。

【讨论】:

  • +1,很高兴看到您再次回答正则表达式问题。在PCRE 中,您甚至可以将其设为++(但您当然知道):)
  • @Unihedron,你是什么意思?你当然可以这样做。例如,this works&lt;(\w++)&gt;(?:[^&lt;&gt;]|(?R))*+&lt;/\1&gt;。 @zx81,最近没有太多时间。 :-)
  • 哇,我不知道(?R) 构造,很好。
【解决方案2】:

这是一个简单的递归下降 xml 解析器,我现在正在制作它,所以它会有点粗糙和准备好,用 ruby​​ 编写它,因为你没有指定语言。 不要在生产中使用它(或任何地方,这只是为了好奇):

string = "<TAG>one<OTHER_TAG>two</OTHER_TAG>one</TAG>"
regex_xml_parser = -> string {
  stuff_before = []
  matches = []
  stuff_after = []
  while string =~ />/
    stuff_before << string[ /^[^<]*/ ]
    string.sub!(/^[^<]*/, '')
    matches << string.match(/<([^>]+)>(.*)<\/\1>/)
    string.sub!(/<([^>]+)>(.*)<\/\1>/, '')
    stuff_after << string[ /[^>]*$/ ]
    string.sub!(/[^>]*$/, '')
    p [ stuff_after, "stuff_after" ]
  end
  values = stuff_before + stuff_after + [string]
  return_value = values.clone
  matching_nodes = matches.map { |match| make_matches[match]}
  {values: return_value.select { |x| x != "" },
  nodes: matching_nodes}
}

make_matches = -> match_item {
  {match_item[1] => regex_xml_parser[match_item[2]]}
}

regex_xml_parser[string]

请记住,我们实际上是在这里构建解析器,所以我认为使用已经存在的解析器会更容易一些。

【讨论】: