Как извлечь заголовки тегов в PHP из строки - PullRequest
5 голосов
/ 14 января 2010

Из строки, которая содержит много HTMl, как я могу извлечь весь текст из тегов <h1><h2>etc в новую переменную.

Возможно использование preg_match_all и отправка совпадений в одну переменную с разделителями-запятыми.

Спасибо, ребята.

Ответы [ 8 ]

5 голосов
/ 14 января 2010

Сначала вам нужно очистить HTML (в примере $ html_str) с помощью tidy:

$tidy_config = array(
    "indent"               => true,
    "output-xml"           => true,
    "output-xhtml"         => false,
    "drop-empty-paras"     => false,
    "hide-comments"        => true,
    "numeric-entities"     => true,
    "doctype"              => "omit",
    "char-encoding"        => "utf8",
    "repeated-attributes"  => "keep-last"
);

$xml_str = tidy_repair_string($html_str, $tidy_config);

Затем вы можете загрузить XML ($ xml_str) в DOMDocument:

$doc = DOMDocument::loadXML($xml_str);

И, наконец, вы можете использовать метод Хории Драгомира:

$list = $doc->getElementsByTagName("h1");
for ($i = 0; $i < $list->length; $i++) {
    print($list->item($i)->nodeValue . "<br/>\n");
}

Или вы можете также использовать XPath для более сложных запросов в DOMDocument (см. http://www.php.net/manual/en/class.domxpath.php)

$xpath = new DOMXPath($doc);
$list = $xpath->evaluate("//h1");
4 голосов
/ 14 января 2010

Когда вопрос «Как извлечь материал из HTML», НИКОГДА не используйте регулярные выражения. Вместо этого см. Обсуждение Надежного, зрелого HTML-парсера для PHP .

3 голосов
/ 23 сентября 2012

Я знаю, что это очень старая запись, однако я хотел бы упомянуть лучший способ, которым я смог коллективно получить заголовки тегов.

<h1>title</h1> and <h2>title 2</h2>

Этот метод (работает как регулярное выражение, однако PHP действует немного по-другому.)

/<\s*h[1-2](?:.*)>(.*)</\s*h/i

используйте это в вашем preg_match

|<\s*h[1-2](?:.*)>(.*)</\s*h|Ui

$group[1] будет включать в себя то, что находится между тегом заголовка. $group[0] это все <h1>test</h

Это будет учитывать пробелы, и если кто-то добавит "class / id"

<h1 class="classname">test</h1>

класс / id (группа) игнорируется.

ПРИМЕЧАНИЕ : Когда я анализирую теги HTML, я всегда удаляю и заменяю все пробелы, разрывы строк, табуляции и т. Д. На 1 пробел. Это минимизирует многострочные, точечные и очень большие пробелы, которые в некоторых случаях могут испортить форматирование регулярных выражений.

  • конечно, я только беру 1-2 тега заголовка, измените это на 0-9, чтобы захватить все.
  • Если у кого-то есть мод для добавления или исправления к моему коду, пожалуйста, ответьте, я бы очень хотел знать.
  • Напротив, Regex плохо работает с HTML, это очень открытый аргумент. Потому что если вы спроектируете свои php-функции и выражения регулярных выражений, чтобы полностью убрать мусор и подготовить HTML-код для определенных выражений регулярных выражений, вы сможете прекрасно получить то, что ищете. Вы можете сделать достаточное количество регулярных выражений, чтобы заменить любительскую работу с HTML.

Вот ссылка на тестовую страницу regex test

3 голосов
/ 14 января 2010

пожалуйста, обратите внимание на нативный DOMDocument класс php.

Вы можете использовать $domdoc->getElementsByTagName('h1'), чтобы получить заголовки.

2 голосов
/ 14 января 2010

Если вы действительно хотите использовать регулярные выражения, я думаю, что:

preg_match_all('/<h[0-6]>([^</h[0-6]>*)</h/i', $string, $matches);

должно работать, пока ваши теги заголовков не вложены. Как уже говорили другие, если вы не контролируете HTML, регулярные выражения - не лучший способ сделать это.

2 голосов
/ 14 января 2010

Возможно, вам лучше использовать анализатор HTML. Но для действительно простых сценариев может подойти что-то подобное:

if (preg_match_all('/<h\d>([^<]*)<\/h\d>/iU', $str, $matches)) {
    // $matches contains all instances of h1-h6
}
2 голосов
/ 14 января 2010

Рекомендуется не использовать регулярные выражения для этой работы и использовать что-либо SimpleHTMLDOM parser

0 голосов
/ 20 июня 2017

Я просто хочу поделиться своим решением:

function get_all_headings( $content ) {
    preg_match_all( '/\<(h[1-6])\>(.*)<\/h[1-6]>/i', $content, $matches );

    $r = array();
    if( !empty( $matches[1] ) && !empty( $matches[2] ) ){
        $tags = $matches[1];
        $titles = $matches[2];
        foreach ($tags as $i => $tag) {
            $r[] = array( 'tag' => $tag, 'title' => $titles[ $i ] );
        }
    }

    return $r;
}

Эта функция вернет пустой массив, если заголовки не найдены или что-то вроде этого:

array (
    array (
        'tag' => 'h1',
        'title' => 'This is a title',
    ),
    array (
        'tag' => 'h2',
        'title' => 'This is the second title',
    ),
)
...