Разработчику. Сборник рецептов PHP
Задавайте вопросы

Сборка текста, заключенного в теги HTML

Вернуться назад

Задача

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

Решение

Прочитайте HTML-файл в строку и используйте в шаблоне непоглощающее сравнение:

$html = join('',file($file));
preg_match('#<h([1-6])>(.+?)</h\1>#is', $html, $matches);

В этом примере элемент $matches[2] содержит массив найденных заголовков.

Обсуждение

Посредством простого регулярного выражения трудно правильно проанализировать HTML-документ. В этом состоит одно из преимуществ XHTML; с его помощью значительно легче проверить действительность (validity) документа и провести анализ.

Так, шаблон в разделе «Решение» достаточно изощрен, чтобы найти только соответствующие заголовки, поэтому <h1>Dr. Strangelove<h1> удовлетворяет шаблону, поскольку он заключен в теги <h1>, а <h2>How I Learned to Stop Worrying and Love the Bomb</h3> не удовлетворяет, так как в качестве открывающего тега использован <h2>, а в качестве закрывающего – другой тег (</h3>).

Эта технология работает также при нахождении текста, заключенного в теги полужирного шрифта и в теги курсива:

$html = join('',file($file));
preg_match('#<([bi])>(.+?)#is', $html, $matches);

Однако это не помогает в случае вложенных заголовков. Применение данного регулярного выражения к следующей строке:

<b>Dr. Strangelove or: <i>How I Learned to Stop Worrying
                            and Love the Bomb</i></b>

не выделяет текст внутри тегов <i> как самостоятельный элемент.

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

Найденный текст можно обработать, выполняя цикл по массиву совпадений. Например, следующий фрагмент кода анализирует документ на предмет заголовков и красиво их печатает с отступами, соответствующими уровню заголовков:

$html = join('',file($file));
preg_match('#<h([1-6])>(.+?)</h\1>#is', $html, $matches);

for ($i = 0, $j = count($matches[0]); $i < $j; $i++) {
     print str_repeat(' ', 2 * ($matches[1][$i]-1)) . $matches[2][$i] . "\n";
}

В случае такого применения этого рецепта к HTML-тексту вида:

$html =<<<_END_
<h1>PHP Cookbook</h1>

Other Chapters
<h2>Regular Expressions</h2>

Other Recipes
<h3>Capturing Text Inside of HTML Tags</h3>

<h4>Problem</h4>
<h4>Solution</h4>
<h4>Discussion</h4>
<h4>See Also</h4>

_END_;

preg_match_all('#<h([1-6])>(.+?)</h\1>#is', $html, $matches);

for ($i = 0, $j = count($matches[0]); $i < $j; $i++) {
        print str_repeat(' ', 2 * ($matches[1][$i]-1)) . $matches[2][$i] . "\n";
}

Получаем:

PHP Cookbook
   Regular Expressions
      Capturing Text Inside of HTML Tags
         Problem
         Solution
         Discussion
         See Also

Выделяя уровень заголовка и сам текст заголовка по отдельности, можно получить прямой доступ к уровню и трактовать его как число при определении размера отступа. Чтобы избежать отступа в два пробела для всех строк, вычтите из уровня 1.

Вернуться назад

Рейтинг@Mail.ru

Яндекс.Метрика

Индекс цитирования

Рейтинг Сайтов ДОСКИ.РУ