【问题标题】:Odd php regex behavior奇怪的 php 正则表达式行为
【发布时间】:2013-07-13 15:03:57
【问题描述】:

尝试使用正则表达式匹配 xml 文档中的单个第一个节点

~<(\S+).*>.*</\1>~,在文本达到一定长度之前它不会匹配任何内容。在一个文档中,在我将文本剥离到 ​​1186 个字符之后,正则表达式成功地找到了一些东西。在下面的示例中,我剥离了文本,直到它只有 960 个字符,然后正则表达式成功。可以想象,这种看似不一致的行为非常令人困惑。我将不胜感激任何有关为什么会发生这种情况的信息。

原文:

<?xml version="1.0"?> <catalog> <book id="bk101"> <author>Gambardella, Matthew</author> <title>XML Developer's Guide</title> <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book> <book id="bk102"> <author>Ralls, Kim</author> <title>Midnight Rain</title> <genre>Fantasy</genre> <price>5.95</price> <publish_date>2000-12-16</publish_date> <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description> </book> <book id="bk103"> <author>Corets, Eva</author> <title>Maeve Ascendant</title> <genre>Fantasy</genre> <price>5.95</price> <publish_date>2000-11-17</publish_date> <description>After the collapse of a nanotechnology society in England, the young survivors lay the foundation for a new society.</description> </book> <book id="bk104"> <author>Corets, Eva</author> <title>Oberon's Legacy</title> <genre>Fantasy</genre> <price>5.95</price> <publish_date>2001-03-10</publish_date> <description>In post-apocalypse England, the mysterious agent known only as Oberon helps to create a new life for the inhabitants of London. Sequel to Maeve Ascendant.</description> </book> <book id="bk105"> <author>Corets, Eva</author> <title>The Sundered Grail</title> <genre>Fantasy</genre> <price>5.95</price> <publish_date>2001-09-10</publish_date> <description>The two daughters of Maeve, half-sisters, battle one another for control of England. Sequel to Oberon's Legacy.</description> </book> <book id="bk106"> <author>Randall, Cynthia</author> <title>Lover Birds</title> <genre>Romance</genre> <price>4.95</price> <publish_date>2000-09-02</publish_date> <description>When Carla meets Paul at an ornithology conference, tempers fly as feathers get ruffled.</description> </book> <book id="bk107"> <author>Thurman, Paula</author> <title>Splish Splash</title> <genre>Romance</genre> <price>4.95</price> <publish_date>2000-11-02</publish_date> <description>A deep sea diver finds true love twenty thousand leagues beneath the sea.</description> </book> <book id="bk108"> <author>Knorr, Stefan</author> <title>Creepy Crawlies</title> <genre>Horror</genre> <price>4.95</price> <publish_date>2000-12-06</publish_date> <description>An anthology of horror stories about roaches, centipedes, scorpions and other insects.</description> </book> <book id="bk109"> <author>Kress, Peter</author> <title>Paradox Lost</title> <genre>Science Fiction</genre> <price>6.95</price> <publish_date>2000-11-02</publish_date> <description>After an inadvertant trip through a Heisenberg Uncertainty Device, James Salway discovers the problems of being quantum.</description> </book> <book id="bk110"> <author>O'Brien, Tim</author> <title>Microsoft .NET: The Programming Bible</title> <genre>Computer</genre> <price>36.95</price> <publish_date>2000-12-09</publish_date> <description>Microsoft's .NET initiative is explored in detail in this deep programmer's reference.</description> </book> <book id="bk111"> <author>O'Brien, Tim</author> <title>MSXML3: A Comprehensive Guide</title> <genre>Computer</genre> <price>36.95</price> <publish_date>2000-12-01</publish_date> <description>The Microsoft MSXML3 parser is covered in detail, with attention to XML DOM interfaces, XSLT processing, SAX and more.</description> </book> <book id="bk112"> <author>Galos, Mike</author> <title>Visual Studio 7: A Comprehensive Guide</title> <genre>Computer</genre> <price>49.95</price> <publish_date>2001-04-16</publish_date> <description>Microsoft Visual Studio 7 is explored in depth, looking at how Visual Basic, Visual C++, C#, and ASP+ are integrated into a comprehensive development environment.</description> </book> </catalog>

修剪(成功)文本:

<?xml version="1.0"?> <catalog> <book id="bk101"> <author>Gambardella, Matthew</author> <title>XML Developer's Guide</title> <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book> <book id="bk102"> <author>Ralls, Kim</author> <title>Midnight Rain</title> <genre>Fantasy</genre> <price>5.95</price> <publish_date>2000-12-16</publish_date> <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description> </book> <book id="bk103"> <author>Corets, Eva</author> <title>Maeve Ascendant</title> <genre>Fantasy</genre> <price>5.95</price> <publish_date>2000-11-17</publish_date> <description>After the collapse of a nanotechnology society in England, the young survivors lay the foundation for a new society.</description> </book> <book id="bk104"> <author>Core</catalog>

对于文本的格式,我深表歉意,但我不想在数据中添加某些内容以使其对其他人表现不同(例如换行符)。

编辑:我一直在使用this 站点测试正则表达式。

【问题讨论】:

  • 为什么是正则表达式?只需使用 PHP 内置的 4 或 5 个 xml 解析器之一
  • 为了科学!看,这不是关于 xml 解析器,而是关于 php 的正则表达式表现出奇怪的行为。我的正则表达式有问题,或者 php 的正则表达式实现有问题,或者有一个选项或我不知道的东西。我只是想知道它为什么会这样。
  • 也许你可以试试pcre.backtrack_limit(使用ini_set)?
  • 我相信 Pieter 的意思是,如果不清楚的话,你的表达可能非常“灵活”,以至于它需要尝试大量的路径(和回溯)才能完全满意它没有找到匹配项,在此之前您可能会遇到限制(回溯限制或内存/时间限制)。
  • 据我所知,问题在于第一个 .* 贪婪。尝试在之后添加?,例如.*?,以使正则表达式仅匹配&gt;,否则它将匹配最后一个&gt;(几乎意味着整个xml文档)。

标签: php regex


【解决方案1】:

嗯,首先 - 一般的态度是不应该用 RegEx 解析 XML。如果可能,请改用 SimpleXML。 正如 nickb 所说,太贪心了……

【讨论】:

  • 虽然我遇到的唯一用例示例是使用 xml 作为文本,但这并不意味着它不能与其他文本一起发生。这不是一个真正的答案 - 这是一个警察。
  • 是的,对不起 - 我更关注“完成工作”而不是正则表达式的细节......
【解决方案2】:

您可以使用约束字符类更好地控制量词:

带有惰性量词的示例:

$pattern = '~<([^>\s]++)[^>]*+>.*?</\1>~';

只有所有格量词的例子(好多了):

$pattern = '~<([^>\s]++)[^>]*+>(?>[^<]++|<(?!/\1>))+</\1>~';

但这两种模式不处理嵌套结构,你必须使用:

$pattern = '~<([^>/\s]++)[^>]*+>(?>[^<]++|(?R))*</\1>~';



详情:

第二种模式:(?&gt;[^&lt;]++|&lt;(?!/\1&gt;))+

(?>           # open an atomic group
   [^<]++     # all characters but < one or more times (possessive)
  |           # OR
   <(?!/\1)   # < not followed by / and the content of the first backreference
              #  (the tag name here)
)+            # close the atomic group and repeat one or more times

这样做的目标是匹配所有直到&lt;/\1&gt;,这个想法是匹配所有不是&lt; 或所有&lt; 后面没有/tagname&gt;

更多关于possessive quantifiersatomic groups的信息。


第三种模式:递归模式

<                                
  ([^>/\s]++)     # tagname, 
                  # note that you must exclude the / to avoid closing tags
  [^>]*+          # leading characters in the tag
>


(?>               # open an atomic group
   [^<]++         # all characters but <, one or more times (possessive)
  |               # OR
   (?R)           # repeat the whole pattern
)*                # close the atomic group, repeat zero or more times

</\1>             # close tag with the first back reference

【讨论】:

  • 你能解释一下发生了什么吗?这很好用,但我不知道发生了什么(至少在第二个中)。
【解决方案3】:

函数preg_match() 具有 - 与许多其他 PHP 函数类似 - 一个返回值。

根据返回值是什么,您可以决定脚本应该如何进行。

在您的情况下,您实际上没有检查返回值为FALSE。因为 - 如您的示例所示,它是 FALSE

阅读手册表明FALSE 的返回值表示错误。您可以通过调用函数preg_last_error() 来了解有关该错误的更多信息,该函数会给出最后一个错误代码。所以你可以learn about the error your call to preg_match() gives:

int(2) - PREG_BACKTRACK_LIMIT_ERROR

参见:

【讨论】:

  • 这确实是我想要的。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 2012-03-02
  • 1970-01-01
相关资源
最近更新 更多