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

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

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

$html = join('',file($file));
preg_match('#(.+?)#is', $html, $matches);

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

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

Так, шаблон в разделе «Решение» достаточно изощрен, чтобы найти только соответствующие заголовки, поэтому

Dr. Strangelove

удовлетворяет шаблону, поскольку он заключен в теги

, а

How I Learned to Stop Worrying and Love the Bomb

не удовлетворяет, так как в качестве открывающего тега использован

, а в качестве закрывающего – другой тег (

).

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

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

Однако это не помогает в случае вложенных заголовков.


Применение данного регулярного выражения к следующей строке:

Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb не выделяет текст внутри тегов как самостоятельный элемент.

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

$html = join('',file($file));
preg_match('#(.+?)#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_

PHP Cookbook


Other Chapters

Regular Expressions


Other Recipes

Capturing Text Inside of HTML Tags


Problem


Solution


Discussion


See Also


_END_;
preg_match_all('#(.+?)#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.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Выбор между поглощающим и непоглощающим сравнением
Нахождение n-го совпадения
Переход от ereg к preg
Поиск в файле всех строк, соответствующих шаблону
Поиск слов

Вернуться в раздел: PHP / 13. Регулярные выражения