正则表达式找不到xml标签内的字符串?

时间:2012-11-19 05:48:45

标签: php xml regex

试图找到这个问题的正则表达式:

PHP parsing xml file error

尝试匹配以下字符串中的“137b”,使用负向前瞻和后观断言:

<Rate Symbol="EURTRY">
    <Bid>2.29443</Bid>
    <Ask>2.29562</Ask>
    <High>2.29841</High>
    <Low>2.28999</Low>

 137b

 <Direction>1</Direction>
    <Last>23:29:11</Last>
</Rate>

任何人都可以指出为什么这个正则表达式不起作用:

(?<!(<\w+>))[a-zA-Z0-9_\.:]+(?!(</\w+>))

意图:包含“a-zA-Z0-9 _:”的字符串前面和后面没有XML标记,所以它应该匹配“137b”,但它不匹配。

以下是正则表达式的链接: http://regexr.com?32rk4

而没有否定断言的相同正则表达式(<\w+>)[a-zA-Z0-9_\.:]+(</\w+>)正确匹配所有字符串WITHIN xml标记。

http://regexr.com?32rk7

2 个答案:

答案 0 :(得分:2)

大多数正则表达式都不支持可变长度的lookbehind。看来就是这种情况。请尝试使用此选项,以匹配所有文本,后跟开始标记而不是结束标记:

[a-zA-Z0-9_\.:]+(?=\s*<)(?!(</\w+>))

毋庸置疑,解析XML的正则表达式方法很脆弱,而且这个方法也不例外。

答案 1 :(得分:0)

PHP不会让你使用lookbehind,但无论如何,lookbehind不会是最好的工具。 (它几乎从来都不是。)你应该能够只用前瞻来解决问题。如果您可以对文档结构做出某些假设,那将会容易得多。例如,您是否可以确定封闭节点始终名为Rate,并且其子节点永远不会拥有自己的子节点(属性或元素)?换句话说,你永远不会看到这样的东西:

<Rate Symbol="EURUSD">
    <Bid>1.27554</Bid>
        <foo>bar</foo>
    <Ask foo="bar">1.27578</Ask>
</Rate>

如果是这样,您可以使用肯定预测来匹配任意数量的完整子节点,然后是结束</Rate>标记:

[a-zA-Z0-9_.:]++(?=\s*(?><(\w+)>[^<]*</\1>\s*)*+</Rate>)

解释:

[a-zA-Z0-9_.:]++
(?=
  \s*
  (?>
    <(\w+)>       # match an opening tag and capture its name
    [^<]*         # consume the content
    </\1>         # match the closing tag
    \s*
  )*+           # do this zero or more times
  </Rate>       # confirm we're inside a <Rate> element
)

这甚至可以扩展到处理你在original question中提到的其他垃圾,但正则表达式变得如此丑陋,我认为这不值得。