RegExp.正在查找特定标记之间的标记


RegExp. Finding tags between specific tag

有一个html代码包含许多href。但我不需要所有的href。我只想得到div中包含的hrefs:

<div class="category-map second-links"> 
*****
</div> <p class="sec">

我想看到的结果:

<a href='xxx'>yyy</a>
<a href='zzz'>www</a>
...

我的版本(不工作):

(?<=<div class='"category-map second-links'">)(.+?(<a href='".+?".+?>.+<'/a>))+(?=<'/div> <p class="sec">)

免责声明:最好使用合适的html解析器。这个答案是出于教育目的,尽管如果它是有效的html:P,它比常见的正则表达式更可靠

Regex太棒了

所以我决定分两部分来做:

  • 匹配<div class="category-map second-links"></div>中的所有内容,即使它是嵌套的
  • 循环这些匹配,并匹配<a></a>,我选择保持简单,因为我不希望链接嵌套

最难的部分

这是正则表达式,我们将使用递归模式和xsi修饰符:

<div's+class's*='s*"'s*category-map's+second-links's*"'s*>    # match a certain div with a certain classes
(?:                                                           # non-capturing group
   (?:<!--.*?-->)?                                            # Match the comments !
   (?:(?!</?div[^>]*>).)                                      # check if there is no start/closing tag
   |                                                          # or (which means there is)
   (?R)                                                       # Recurse the pattern, it's the same as (?0)
)*                                                            # repeat zero or more times
</div's*>                                                     # match the closing tag
(?=.*?<p's+class's*='s*"'s*sec's*"'s*>)                       # make sure there is <p class="sec"> ahead of the expression

修改器:

  • s:使模式中的点元字符与所有字符(包括换行符)匹配
  • x:模式中的空白数据字符将被完全忽略,除非转义或在字符类内,字符类外未转义的#和下一个换行符(包括换行符)之间的字符也将被忽略。这相当于Perl的/x修饰符,可以在复杂的模式中包含注释
  • i:不区分大小写匹配

简单的部分

如果没有像<a title="</a>"></a>:这样疯狂的东西,匹配未测试的a标签并没有那么困难

<a[^>]*>    # match the beginning a tag
.*?         # match everything ungreedy until ...
</a's*>     # match </a       > or </a>
# Not forgetting the xsi modifiers

用PHP封装所有内容

$input = '<div class="category-map second-links"> 
*****
    <!--<div class="category-map second-links"> Comment hacks --> 
    <div class="category-map second-links">
        <a href=''xxx''>yyy</a>
        <a href=''zzz''>www</a>
...
    </div>
<div class="category-map second-links"> 
*****
    <!--<div class="category-map second-links"> Comment hacks --> 
    <div class="category-map second-links">
        <a href=''aaa''>bbb</a>
        <a href=''ccc''>ddd</a>
...
    </div>
</div> <p class="sec">';
$links = array();
preg_match_all('~
<div's+class's*='s*"'s*category-map's+second-links's*"'s*>    # match a certain div with a certain classes
(?:                                                           # non-capturing group
   (?:<!--.*?-->)?                                            # Match the comments !
   (?:(?!</?div[^>]*>).)                                      # check if there is no start/closing tag
   |                                                          # or (which means there is)
   (?R)                                                       # Recurse the pattern, it''s the same as (?0)
)*                                                            # repeat zero or more times
</div's*>                                                     # match the closing tag
(?=.*?<p's+class's*='s*"'s*sec's*"'s*>)                       # make sure there is <p class="sec"> ahead of the expression
~sxi', $input, $matches);
if(isset($matches[0])){
    foreach($matches[0] as $match){
        preg_match_all('~
                            <a[^>]*>    # match the beginning a tag
                            .*?         # match everything ungreedy until ...
                            </a's*>     # match </a       > or </a>
                        ~isx', $match, $tempLinks);
        if(isset($tempLinks[0])){
            array_push($links, $tempLinks[0]);
        }
    }
}
if(isset($links[0])){
    print_r($links[0]);
}else{
    echo 'empty :(';
}

在线演示

硬质部分简易部件PHP代码

参考文献

  • PHP正则表达式修饰符
  • 递归模式
  • 解释递归模式

如果将HTML加载到DOM文档中,则可以使用Xpath从中查询节点。

文档中的所有a元素:

  • //a

具有祖先/父div元素的:

  • //a[ancestor:div]

具有类别属性category-map second-links

  • //a[ancestor::div[@class = "category-map second-links"]]

获取过滤后的a元素的href属性(可选)

  • //a[ancestor::div[@class = "category-map second-links"]]/@href

完整示例:

$html = <<<'HTML'
<div class="category-map second-links"> 
*****
    <!--<div class="category-map second-links"> Comment hacks --> 
    <div class="category-map second-links">
        <a href='xxx'>yyy</a>
        <a href='zzz'>www</a>
...
    </div>
<div class="category-map second-links"> 
*****
    <!--<div class="category-map second-links"> Comment hacks --> 
    <div class="category-map second-links">
        <a href='aaa'>bbb</a>
        <a href='ccc'>ddd</a>
...
    </div>
</div> <p class="sec">
HTML;
$dom = new DOMDocument();
$dom->loadHtml($html);
$xpath = new DOMXpath($dom);
// fetch the href attributes
$hrefs = array();
foreach ($xpath->evaluate('//a[ancestor::div[@class = "category-map second-links"]]/@href') as $node) {
  $hrefs[] = $node->value;
}
var_dump($hrefs);
// fetch the a elements an read some data from them
$linkData = array();
foreach ($xpath->evaluate('//a[ancestor::div[@class = "category-map second-links"]]') as $node) {
  $linkData[] = array(
    'href' => $node->getAttribute('@href'),
    'text' => $node->nodeValue,
  );
}
var_dump($linkData);
// fetch the a elements and store their html
$links = array();
foreach ($xpath->evaluate('//a[ancestor::div[@class = "category-map second-links"]]') as $node) {
  $links[] = $dom->saveHtml($node);
}
var_dump($links);

使用simpledomhtml

// Create DOM from URL
$html = file_get_html('<YOU_WEBSITE_URL_HERE>');
// Find specific tag
foreach($html->find('div.category-map.second-links a') as $anchor) {
    $anchors[] = $anchor;
}
print_r($anchors);

如果您想使用Regex,那么您可能会使用两个Regex查询一个用于获取所有div,另一个用于在每个div中查找href。

因为在像这样的单一查询中

"<div.*?<a href='(?<data>.*?)'.*?</div>"

如果任何div有多个href,则只能得到一个href。

所以你可以使用dom

$dom->find('div a')->attrib('href');

我不确定上面的dom是否100%有效,但我给你这个提示,希望你能为你做一个合适的