首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用正则表达式匹配具有特定ID的div块

使用正则表达式匹配具有特定ID的div块
EN

Stack Overflow用户
提问于 2011-03-19 01:08:24
回答 5查看 9.9K关注 0票数 4

我正在尝试匹配一个具有特定id的div块。下面是我的正则表达式代码:

代码语言:javascript
复制
<div\s+[^>]*\s*id\s*=\s*["|']content["|']\s*>[^/div]+

我希望正则表达式与整个div块相匹配。所以我把^/div+放在我的正则表达式中,我假设它会匹配剩余的字符,直到它到达结尾,但它直到结尾才匹配,因为^表达式认为我不想匹配中的任何字符。我想要的是把整个事情看作一个whole.Putting,a ^()也没有用..

所以请告诉我该如何编码这个问题

代码语言:javascript
复制
<div id="content">
    <noscript></noscript>
    <a href="blabla.com">
    <h1>
       <a href="blablac.com">Blablabla</a>
    </h1>
</div>
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-03-19 08:49:21

免责声明:首先,我同意,一般来说,正则表达式不是解析HTML语言的最佳工具。然而,在正确的人手中(有几个警告),Philip Hazel强大的(并且最肯定不是REGULAR的) PCRE库(由PHP的preg_*()系列函数使用)确实允许解决像这样的重要数据抓取问题(有一些限制和警告-见下文)。上面提到的问题单独使用正则表达式解决起来特别复杂,而且下面给出的正则表达式解决方案并不适用于所有人,不应该由正则表达式新手尝试。要正确理解下面的答案,需要对几个高级正则表达式结构和技术有相当深入的理解。

Won‘t孩子们!是的,我读过博本斯的传奇答案,我知道这是一个敏感的话题(至少可以这么说)。但是,如果你想立即点击向下投票箭头,因为我是'/(?:actual|brave|stupid)ly/',同时使用了:REGEX和:HTML (并且在一个非常重要的问题上也是如此),我谦虚地请你克制足够长的时间来阅读整篇文章,并亲自尝试这个解决方案。

考虑到这一点,如果您想了解如何构建高级正则表达式来解决此问题,(除了少数(不太可能的)特殊情况--请参阅下面的示例),请继续阅读...

一个高级的递归REGEX解决方案:正如Wes Hardaker正确地指出,DIV可以(并且经常是)嵌套的。然而,他并不是100%正确的,他说“你不能构造一个匹配的,直到正确的”。事实是,使用PHP,您可以做到!(有一些限制-见下文)。与Perl和.NET一样,PHP中的PCRE regex引擎提供了递归表达式(即(?R)(?1)(?2)等),允许匹配任意深度的嵌套结构(仅限于内存)。例如,您可以很容易地将平衡的嵌套括号与以下表达式匹配:'/\((?:[^()]++|(?R))*+\)/'。如果您有任何疑问,请运行这个简单的测试:

代码语言:javascript
复制
$text = 'zero(one(two)one(two(three)two)one)zero';
if (preg_match('/\((?:[^()]++|(?R))*+\)/', $text, $matches)) {
    print_r($matches);
}

因此,如果我们都同意PHP正则表达式确实可以匹配嵌套结构,那么让我们来看看手头的问题。由于最外层的DIV必须具有id="content"属性,但任何嵌套的DIV可能有也可能没有,这一特定问题变得复杂起来。因此,我们不能使用(?R)递归匹配整个表达式结构,因为匹配外部DIV的子表达式与匹配内部DIV所需的子表达式不同。在这种情况下,我们需要一个捕获组(在本例中为Group2),它将充当一个“递归子例程”,它将匹配内部嵌套的DIV。使用高级正则表达式,该正则表达式可以正确地匹配(在大多数情况下-请参见下文)具有id="content"DIV,其本身可能包含嵌套的DIV

代码语言:javascript
复制
$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]);
}

正如我所说的,这个正则表达式相当复杂,但请放心,它确实可以工作!除了下面提到的一些不太可能的情况--(可能还有更多的情况,如果你能找到的话,我将非常感激)。尝试一下,自己去看看吧!

我应该使用这个吗?在必须以100%的可靠性和准确性解析成百上千个文档的生产环境中使用这个正则表达式解决方案是否合适?当然不是。它对于有限的一次运行一些HTML文件有用吗?(例如,可能是问这个问题的人?)有可能。这取决于人们对高级正则表达式的适应程度。如果上面的正则表达式看起来像是用外语编写的(它确实是),并且/或者吓到您了,答案可能是否定的。

它能工作吗?是的。例如,给定以下测试数据,上面的正则表达式正确地选择了具有id="content"DIV (或id='content'id=content ):

代码语言:javascript
复制
<!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>

警告:那么这种解决方案不起作用的情况是什么呢?嗯,DIV开始标记的任何属性中可能没有任何尖括号(可以消除这个限制,但这会增加代码中的更多内容)。下面的CDATA跨度包含我们正在寻找的特定DIV开始标记(极不可能),它们将导致正则表达式失败:

代码语言:javascript
复制
<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 ]]>

我非常想知道其他人的情况。

GO READ MRE3正如我之前所说,要真正掌握这里发生的事情,需要对几种高级技术有相当深入的理解。这些技术既不明显也不直观。据我所知,只有一种方法可以获得这些技能,那就是坐下来学习: Jeffrey Friedl (MRE3)的Mastering Regular Expressions (3rd Edition)。(您会很高兴这样做的!)

我可以诚实地说,这是我一生中读过的最有用的书!

干杯!

EDIT 2013-04-30固定正则表达式。它以前不允许紧跟在DIV开始标记后面的非DIV标记。

票数 22
EN

Stack Overflow用户

发布于 2011-03-19 01:12:28

当^/div+到达这些字符中的任何一个时,它将停止,这不是您想要的。因为当它到达时也会因为i而停止。

不幸的是,如果不知道HTML的内部结构,您就不能做您想做的事情。请考虑以下内容:

代码语言:javascript
复制
<div id="content">
  <div id="somethingelse">
  </div>
</div>

即使可以构造一个匹配到</div>的正则表达式,也不能构造一个匹配到正确</div>的正则表达式。您需要进行更密集的解析。

票数 3
EN

Stack Overflow用户

发布于 2011-03-19 02:41:54

使用解析器,而不是正则表达式。

下面是一个PHP示例:http://htmlparsing.com/php.html

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5355452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档