我正在尝试匹配具有特定id的div块.这是我的正则表达式代码:
<div\s+[^>]*\s*id\s*=\s*["|']content["|']\s*>[^/div]+
Run Code Online (Sandbox Code Playgroud)
我希望正则表达式匹配整个div块.所以我把[^/div] +放在我的正则表达式中,我假设它会匹配剩余的字符,直到它到达结尾但是它不能匹配直到结束,因为[^]表达式认为我不想要匹配任何</ | d | 我| v | >.我想要的是将整个事情视为一个整体.放置一个[^()]也没有帮助.
所以请告诉我如何编码这个问题
<div id="content">
<noscript></noscript>
<a href="blabla.com">
<h1>
<a href="blablac.com">Blablabla</a>
</h1>
</div>
Run Code Online (Sandbox Code Playgroud)
rid*_*ner 22
免责声明:首先,我同意,一般来说,正则表达式不是解析 HTML 的最佳工具.然而,在右手,(并带有一些告诫),菲利普·黑兹尔强大的(也是最稳妥的非 - 常规)PCRE库(由PHP的使用preg_*()家庭的功能),并允许解决复杂数据刮类似这样的问题一个(有一些限制和警告 - 见下文).单独使用正则表达式解决上述问题特别复杂,并且下面介绍的正则表达式解决方案并非适用于所有人,并且绝不应该由正则表达式新手尝试.要正确理解下面的答案,需要对几种高级正则表达式构造和技术进行相当深入的理解.
请不要有人想到孩子们!是的,我读过bobince的传奇回答,我知道这是一个敏感的话题(至少可以说).但请,如果你想立即点击向下投票箭头,因为我正在'/(?:actual|brave|stupid)ly/'使用单词:REGEX和:HTML同一口气(以及一个非平凡的问题),我会谦虚地问你要克制了足够长的时间来阅读整个帖子并实际尝试解决这个问题.
考虑到这一点,如果您想了解如何制作高级正则表达式来解决这个问题,(对于除少数(不太可能)的特殊情况之外的所有情况 - 请参阅下面的示例),请继续阅读...
高级回归解决方案:正如Wes Hardaker正确指出的那样,DIVs可以(通常是)嵌套.然而,当他说"你不能构造一个在正确的</ div>之前匹配的那个"时,他并非100%正确.事实是,使用PHP,你可以!(有一些限制 - 见下文).如Perl和.NET,PHP中PCRE正则表达式引擎提供递归表达式(即(?R),(?1),(?2)等),其允许匹配嵌套结构到任意深度(仅受存储器限制).例如,您可以轻松地将平衡嵌套括号与此表达式匹配:'/\((?:[^()]++|(?R))*+\)/'.如果您有任何疑问,请运行此简单测试:
$text = 'zero(one(two)one(two(three)two)one)zero';
if (preg_match('/\((?:[^()]++|(?R))*+\)/', $text, $matches)) {
print_r($matches);
}
Run Code Online (Sandbox Code Playgroud)
因此,如果我们都同意PHP正则表达式确实可以匹配嵌套结构,那么让我们继续讨论手头的问题.由于最外层DIV必须具有id="content"属性,但任何嵌套的DIVs可能有也可能没有,这个特殊问题很复杂.因此,我们不能使用(?R) 递归匹配整个表达式构造,因为匹配外部DIV的子表达式与匹配内部DIVs 所需的子表达式不同.在这种情况下,我们需要一个捕获组(在本例中为第2组),它将作为"递归子例程",匹配内部嵌套DIV的.所以这里有一个经过测试的PHP代码片段,运行一个高级的非虚弱但完全评论的 - 所以 - 你可能实际上能够制作一些 -感测外的它的正则表达式,其正确地匹配(在大多数情况下-参见下文),一个DIV具有id="content",其可以本身包含嵌套DIVS:
$re = '% # Match a DIV element having id="content".
<div\b # Start of outer DIV start tag.
[^>]*? # Lazily match up to id attrib.
\bid\s*+=\s*+ # id attribute name and =
([\'"]?+) # $1: Optional quote delimiter.
\bcontent\b # specific ID to be matched.
(?(1)\1) # If open quote, match same closing quote
[^>]*+> # remaining outer DIV start tag.
( # $2: DIV contents. (may be called recursively!)
(?: # Non-capture group for DIV contents alternatives.
# DIV contents option 1: All non-DIV, non-comment stuff...
[^<]++ # One or more non-tag, non-comment characters.
# DIV contents option 2: Start of a non-DIV tag...
| < # Match a "<", but only if it
(?! # is not the beginning of either
/?div\b # a DIV start or end tag,
| !-- # or an HTML comment.
) # Ok, that < was not a DIV or comment.
# DIV contents Option 3: an HTML comment.
| <!--.*?--> # A non-SGML compliant HTML comment.
# DIV contents Option 4: a nested DIV element!
| <div\b[^>]*+> # Inner DIV element start tag.
(?2) # Recurse group 2 as a nested subroutine.
</div\s*> # Inner DIV element end tag.
)*+ # Zero or more of these contents alternatives.
) # End 2$: DIV contents.
</div\s*> # Outer DIV end tag.
%isx';
if (preg_match($re, $text, $matches)) {
printf("Match found:\n%s\n", $matches[0]);
}
Run Code Online (Sandbox Code Playgroud)
正如我所说,这个正则表达式非常复杂,但请放心,它确实有效!除了下面提到的一些不太可能的情况 - (如果你能找到的话,我可能会感激不尽).试一试,亲眼看看吧!
我应该用这个吗?在生产环境中使用此正则表达式解决方案是否合适?是否必须以100%的可靠性和准确性解析数百或数千个文档?当然不是.对于某些HTML文件的有限一次运行它是否有用?(例如可能是提出这个问题的人?)可能.这取决于高级正则表达式的舒适程度.如果上面的正则表达式看起来像是用外语写的(它是),和/或吓跑你的狄更斯,答案可能是否定的.
有用?是.例如,给定下面的测试数据,正则表达式上述正确地挑选出的DIV具有id="content"(或id='content'或id=content就此而言):
<!DOCTYPE HTML SYSTEM>
<html>
<head><title>Test Page</title></head>
<body>
<div id="non-content-div">
<h1>PCRE does recursion!</h1>
<div id='content'>
<h2>First level matched</h2>
<!-- this comment </div> is tricky -->
<div id="one-deep">
<h3>Second level matched</h3>
<div id=two-deep>
<h4>Third level matched</h4>
<div id=three-deep>
<h4>Fourth level matched</h4>
</div>
<p>stuff</p>
</div>
<!-- this comment <div> is tricky -->
<p>stuff</p>
</div>
<p>stuff</p>
</div>
<p>stuff</p>
</div>
<p>stuff</p>
</body></html>
Run Code Online (Sandbox Code Playgroud)
CAVEATS:那么这个解决方案不起作用的场景是什么?好吧,DIV开始标签可能在其任何属性中都没有任何尖括号(可以删除此限制,但这会为代码增加更多).以下CDATA跨度包含DIV我们正在寻找的特定开始标记(极不可能),将导致正则表达式失败:
<style type="text/css">
p:before {
content: 'Unlikely CSS string with <div id=content> in it.';
}
</style>
<p title="Unlikely attribute with a <div id=content> in it">stuff</p>
<script type="text/javascript">
alert("evil script with <div id=content> in it">");
</script>
<!-- Comment with <div id="content"> in it -->
<![CDATA[ a CDATA section with <div id="content"> in it ]]>
Run Code Online (Sandbox Code Playgroud)
我非常想知道其他任何人.
GO READ MRE3正如我之前所说,要真正掌握这里发生的事情需要对几种先进技术有相当深刻的理解.这些技术不明显或不直观.我知道只有一种方法可以获得这些技能,那就是坐下来学习:掌握正则表达式(第3版)作者:Jeffrey Friedl(MRE3).(你会很高兴的!)
老实说,这是我一生中读过的最有用的书!
干杯!
编辑2013-04-30固定正则表达式.它之前不允许DIV紧跟在DIV开始标记之后的非标记.