【问题标题】:Regular Expression To Match Header Tags Not In Specific Div正则表达式匹配不在特定 div 中的标题标签
【发布时间】:2020-03-05 20:14:13
【问题描述】:

所以我的 PHP 代码可以输出如下所示的 HTML:

<div class="wrapper">
<h2>This is a header</h2>
<h2>This is one too/h2>
<h4>Here's one</h4>
<div class="ignore">
<h5>I'm one in here too</h5>
</div>
</div>

我正在尝试做的是 preg_match_all 的标题标签。我的正则表达式(&lt;h([1-6]{1})[^&gt;]*)&gt;.*&lt;\/h\2&gt; 会适当地返回所有这些,但我不想使用“忽略”类来获取 div 中的标题。我正在阅读有关负前瞻的信息,但它变得棘手。任何有帮助的人将不胜感激。

期望的输出:

<h2>This is a header</h2>
<h2>This is one too/h2>
<h4>Here's one</h4>

注意我也是这里的一员,因为它被包裹在带有“ignore”类的 div 中。

【问题讨论】:

  • 如果它是一个选项,例如使用 DOMDocument 而不是正则表达式
  • Lookbehinds / lookaheads 听起来像是正确的方向。到目前为止,您对它们进行了哪些尝试,您对它们的确切问题是什么? SO 上的人不会为您编写代码
  • 我不是在找人为我编码。我正在寻找一个可能的解决方案。编写 RE 是为了像我想要的那样抓取标题。我只是不明白在哪里放置限定符以省略忽略 div 中的标题标签。
  • 你能分享想要的输出吗?
  • @EnricoMariaDeAngelis 为所需的输出在上面进行了编辑。

标签: php regex preg-match


【解决方案1】:

不要在这里乱用正则表达式 - 结合 DOMDocument 查询来释放xpath 的力量:

<?php
$html = <<<EOT
<div class="wrapper">
<h2>This is a header</h2>
<h2>This is one too</h2>
<h4>Here's one</h4>
<div class="ignore">
<h5>I'm one in here too</h5>
</div>
</div>
EOT;

$doc = DOMDocument::loadHTML($html);
$xpath = new DOMXpath($doc);
$headers = $xpath->query("
    //div[not(contains(@class, 'ignore'))]
    /*[self::h2 or self::h4 or self::h5]");

foreach ($headers as $header) {
    echo $header->nodeValue . "\n";
}

?>

这将产生

This is a header
This is one too
Here's one

【讨论】:

  • 感谢您的回答。下次我会使用这个解决方案。
【解决方案2】:

使用DOMDocumentDOMXPath

$html = <<<'HTML'
<div class="wrapper">
<h2>This is a header</h2>
<h2>This is one too</h2>
<h4>Here's one</h4>
<div class="ignore">
<h5>I'm one in here too</h5>
</div>
</div>
HTML;

$dom = new DOMDocument;
$dom->loadHTML($html);
$xp = new DOMXPath($dom);

$nodeList = $xp->query('
//*
[contains(";h1;h2;h3;h4;h5;h6;", concat(";", local-name(), ";"))]
[not(ancestor::div[
    contains(concat(" ", normalize-space(@class), " "), " ignore ")
    ])
]');

foreach ($nodeList as $node) {
    echo 'tag name: ', $node->nodeName, PHP_EOL,
         'html content: ', $dom->saveHTML($node), PHP_EOL,
         'text content: ', $node->textContent, PHP_EOL,
         PHP_EOL;
}

demo

如果您对 XPath 不满意,请查看 zvon tutorial

【讨论】:

  • 谢谢。下次我肯定会用这个。
【解决方案3】:

由于您指定要使用 preg_match() 执行此操作,因此这里是一个否定后视的示例(即过滤掉那些不以 XYZ 开头的事件):https://regex101.com/r/FeAsuj/1

lookbehind 本身是 (?&lt;!&lt;div class=\"ignore\"&gt;)

但在 test-sn-p 中,请注意:

如果您必须继续使用正则表达式,请考虑采用两步法:

  • 第 1 步,您使用 preg_replace() 删除所有不需要的部分。
  • 第 2 步,使用现有的正则表达式。

一般来说,我会同意其他海报以避免正则表达式,并使用 HTML 解析器。

【讨论】:

  • 非常感谢您抽出宝贵的时间帮助我进行回顾。我用前瞻的方式打了自己的头,感谢你没有让我偏离我的道路。
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多