试图找到这个问题的正则表达式:
尝试匹配以下字符串中的“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标记。
答案 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中提到的其他垃圾,但正则表达式变得如此丑陋,我认为这不值得。