Регулярное выражение для соответствия тегам заголовка, отсутствующим в спецификациях c Div - PullRequest
0 голосов
/ 05 марта 2020

Итак, у меня есть 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 из тегов заголовка. Мое регулярное выражение (<h([1-6]{1})[^>]*)>.*<\/h\2> возвращает их все соответствующим образом, но я не хочу захватывать заголовки, которые находятся в div, с классом «ignore». Я читал о негативных взглядах, но это становится сложно. Любой с помощью будет оценен.

Желаемый вывод:

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

Обратите внимание, я тоже здесь опущен, потому что он заключен в div с классом "ignore".

Ответы [ 3 ]

2 голосов
/ 05 марта 2020

С DOMDocument и DOMXPath:

$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;
}

демо

Если вы не знакомы с XPath, взгляните на zvon tutorial .

2 голосов
/ 05 марта 2020

Не связывайтесь с регулярными выражениями здесь - развяжите sh мощность 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
0 голосов
/ 06 марта 2020

Поскольку вы указываете, что хотите сделать это с помощью preg_match (), здесь приведен пример негативного просмотра (т. Е. Отфильтровывает те вхождения, НЕ предшествующие XYZ): https://regex101.com/r/FeAsuj/1

Самым внешним видом является (?<!<div class=\"ignore\">).

Но в тестовом фрагменте обратите внимание, как:

Если вы ДОЛЖНЫ продолжать работать с регулярными выражениями, рассмотрите двухэтапный подход :

  • шаг 1, вы используете preg_replace () для удаления всех ненужных разделов.
  • шаг 2, используйте существующее регулярное выражение.

В общем, я бы согласился с другими авторами, чтобы избежать регулярных выражений, и go с парсером HTML.

...