Часто в веб-приложениях встречается задача извлечения текста из HTML-страницы. В предыдущем разделе были рассмотрены приемы извлечения параметров из тегов <a> и <img>. Рассмотрим извлечение названия страницы, заключенное между тегами <title> и </title>. Эту задачу выполнит ниже следующий скрипт:
<?php
$text="<html><head><title>Название страницы</title></head><body><p>Текст в абзаце</p>текст без абзаца</body></html>";
$patern="#<[\s]*title[\s]*>([^<]*)<[\s]*/title[\s]*>#i";
if(preg_match($patern, $text, $matches)) echo $matches[1];
else echo "Ничего не найдено";
?>
В окне веб-браузера это будет выглядеть ТАК.
Точно так же можно извлечь информацию из других тегов, например, текст между тегами <p> и </p> можно извлечь при помощи следующего скрипта:
<?php
$text="<html><head><title>Название страницы</title></head><body><p>Текст в абзаце</p>текст без абзаца</body></html>";
$patern="#<[\s]*p[\s]*>([^<]*)<[\s]*/p[\s]*>#i";
if(preg_match($patern, $text, $matches)) echo $matches[1];
else echo "Ничего не найдено";
?>
В окне веб-браузера это будет выглядеть ТАК.
Еще одна распространенная задача — преобразование прямых кавычек (") на парные кавычки ("и"). Эту задачу решает следующий скрипт:
<?php
$string =' "Разный" "текст". Мда ... кавычек может быть много. "" ';
$pattern='|"([^"]*)"|i';
$replacement=""\\1"";
echo preg_replace($pattern, $replacement, $string);
?>
В окне веб-браузера это будет выглядеть ТАК.
Часто требуется использование своих собственных тегов, которые могут приобретать довольно сложную форму. Например, пусть в тексте присутствуют теги, имещие следующий синтаксис:
[d]2D5+8[\d]
Данный тег применяется в ряде ролевых интернет-игр. Необходимо извлеч из тега все три числа и получить по ним результат, который вычисляется по следующему алгоритму:
$sum=0;
for($i=0; $i<2; $i++) $sum=$sum+rand(1,5);//случайное число от 1 до 5
$sum=$sum+8;
Данную задачу удобно решать при помощи функции preg_replace_callback().
Пример:
<?php
//текст для разборa
$text="текст текст текст [d]2D5+8[\d] текст текст [D]1d4+1[\D]";
//функция обратного вызова
function summ_number($matches)
{
//как обычно:$matches[0]-полное вхождение шаблона
/*$matches[1] - вхождение первой подмаски заключенной в круглые скобки*/
for($i=1; $i<$matches[2]; $i++)$sum=rand(1,$matches[3])+1;
$sum=$sum+$matches[4];
$result=$matches[1]." = ".$sum;
return $result;
}
echo preg_replace_callback("|\[d][s]*(([0-9]+)D([0-9]+)\+([0-9]+))[\s]*\[\d]|i", summ_number, $text);
?>
В данном примере используется функция обратного вызова summ_number(), имя которой передается в качестве второго аргумента функции preg_replace_callback(). Функция принимает массив с результатами поиска и осуществляет вычисления, возвращая строку с результатом, который подставляется вместо найденной подстроки.
РНР имеет две стандартные функции для подсветки кода highlight_string() и highlight_file(). Данные функции имеют два недостатка: поддерживается только подсветка РНР-кода и только кода размещенного между тегами <?php и ?>(а так же <? и ?>). Поэтому в большинстве случаев приходится применять собственную функцию подсветки синтаксиса.
Рассмотрим пример построения простейших аналогов функции highlight_string() и highlight_file(), реализующих собственную схему подсветки кода и, следовательно, допускающих реализацию подсветки синтаксиса языков, отличных от РНР. Создадим функцию shighlight(), которая будет принимать в качестве параметра строку, содержащую код РНР. Функция fhighlight() будет принимать имя файла с РНР-скриптом. Обе функции будут возвращать строки с разметкой HTML, обеспечивающий подсветку синтаксиса. Функции должны, по возможности, подсвечивать максимальное количество элементов.
Построение функции подсветки следует решать с привлечением регулярных выражений, специально созданных для такого рода задач.
Код функции:
<?php
function shighlight($document)
{
//преобразуем угловые скобки для отображения HTML-тегов. Заменяем строку поиска на строку замены
$document=str_replace("<", "<", $document);
$document=str_replace(">", ">", $document);
/*преобразуем теги <?php и ?>*/
$tegs=array("'<\?php'si","'<\?'si","'\?>'si");
$replace=array("<font color= #95001E><?php</font>",
"<font color= #95001E><?php</font>",
"<font color= #95001E><?php</font>");
$document=preg_replace($tegs, $replace, $document);
//преобразуем комментарии
$document=preg_replace("'((?:#|//)[^\n]*|/\*.*?\*/)'si",
"<font color =#244ECC>\\1</font>",
$document);
//осуществляем переносы строк
$document=preg_replace("'(\n)'si","<br>\\1", $document);
//преобразуем функции
$document=preg_replace("'([\w]+)([\s]*)[\(]'si",
"<font color=#0000CC><b>\\1</b></font>\\2(",
$document);
//преобразуем операторы
$separator=array("'\,'si",
"'\-'si",
"'+'si",
"'\('si",
"'\)'si",
"'\{'si",
"'\}'si");
$replase=array("<font color=#1A691A>,</font>",
"<font color=#1A691A>-</font>",
"<font color=#1A691A>+</font>",
"<font color=#1A691A>(</font>",
"<font color=#1A691A>)</font>",
"<font color=#1A691A>{</font>",
"<font color=#1A691A>}</font>");
$document=preg_replace($separator, $replase, $document);
//преобразуем переменные РНР
$document=preg_replace("'([\S]{1,2}[A-Za-z_]+)'si",
"<b><font color=#000000>\\1</font></b>", $document);
//преобразуем строки, заключенные в одинарные и двойные кавычки
$str=array("'(\"[^\"]*\")'si", "'(\'[^\']*\')'si");
$replase=array("<font color =#FFCC00>\\1</font>",
"<font color =#FFCC00>\\1</font>");
$document=preg_replace($str, $replase, $document);
//преобразуем зарезервированные слова
$str=array("'(echo)'si",
"'(print)'si",
"'(while)'si",
"'(for)'si",
"'(if)'si",
"'(else)'si",
"'(switch)'si",
"'(function)'si",
"'(array)'si");
$replase=array_fill(0, count($str),
"<b><font color=#0000CC>\\1</font></b>");
$document=preg_replace($str, $replase, $document);
//возвращаем результат работы функции
return "<code>$document</code>";
}
?>
Работа функции начинается с преобразования угловых скобок < и > в их HTML- представлении: < и > соответственно.
Следующим этапом является подсветка тегов <?php и ?> и <? и ?> темно-красным цветом. Так как на предыдущем этапе все угловые скобки были преобразованы, то регулярные выражения для этих трех тегов приобретают вид: '<\?php'si, '<\?si,'\?>si. Эта операция осуществляется при помощи функции preg_replace(), принимающей в качестве первых двух параметров массив регулярных выражений в стиле языка Реrl и массив со строками замены. В качестве третьего параметра выступает строка, в которой осуществляется замена. После преобразования тегов РНР происходит подсветка комментариев РНР светло-синим цветом. Регулярное выражение, ответственное за такое преобразование
((?:#|//)[^\n]*|/\*.*?\*/)'si
можно разбить на три части. Подвыражение /\*.*?\*/ ответственно за подсветку многострочечных комментариев в стиле языка С (/**/) — символы экранируются обратным слешем (\), а между последовательностями /* и */ допускается произвольное число любых символов (.*?). Подвыражение
((?:#|//)[^\n]*
является ответственным за однострочные комментарии: //(стиль С++) и # (стиль командных оболочек), после которых следует произвольное количество символов(включая их отсутствие), не содержащих символ перевода строки — [^\n]*. Последовательность ?: предписывает не сохронять результаты для данных круглых скобок. Это позволяет не задумываться о числе сохраненных результатов и замене с использованием функции preg_replace(), а во втором параметре использовать единственный сохраненный результат \\1, который относится к внешним круглым скобкам.
Для осуществления переноса строки все символы переноса строки (\n) предваряются HTML-тегом переноса строки — <br>. Такой прием позволяет сохранить форматирование исходного текста РНР- программы и отразить его в окне браузера.
Следующим этапом является подстветка функций. В РНР существует огромное число функций. Кроме того, в программах можно вводить собственные функции. Поэтому создание списка возможных функций нецелесоообразно. Все функции объединяет то, что после их объявления обязательно следует список параметров в круглых скобках, который, в общем случае, может быть пустым. Между именем функции и скобкой может быть произвольное число пробельных символов или даже переводы строк, поэтому регулярное выражение принимает вид:
([\w]+)([\s]*)[\(]'si
Имя функции состоит из одного или более символа, включающего обобщенный символ слов ([\w]+), после которого следует произвольное количество обобщенных пробелов ([\s]*) и экранированный символоткрывающей круглой скобки [\(].
Примечание. Обобщенный символ слова [\w] эквивалентен [a-Az-Z0-9_], а символ обобщенного пробела [\s] — [ \f\n\r\t\v].
Во втором параметре функции preg_replace() используется результат, сохраненный в круглых скобках: \\1 соответствует имя функции, \\2 — пробелы между именем и открывающей круглой скобкой.
После этого происходит подсветка операторов темно-зеленым цветом.
Заключительный этап состоит в подсветке темно-синим цветом зарезервированных ключевых слов языка Заключительный этап состоит в подсветке темно-синим цветом зарезервированных ключевых слов языка РНР, таких как while, if, else и т.д. Так как выделить эти ключевые слова на фоне других элементов программы достаточно сложно, они помещаются в массив и обрамляется круглыми скобками, что обеспечивает сохранение их в качестве первого параметра (\\1). Массив замены $replase, выступающий в качестве второго аргумента функции preg_replace(), автоматически формируется при помощи функции array_fill(). Для обеспечения подсветки других языков программирования в массив $str необходимо добавить зарезервированные в этих языках слова.
После построения строковой функции подсветки синтаксиса языка РНР не составляет труда создать файловую версию этой функции — fhighlight().
Код функции:
<?php
function fhighlight($filename){
//открываем файл, имя которого передано в параметре $filename
$file=fopen($filename, "r");
//помещаем его содержимое в буфер $document
$document=fread($file, filesize($filename));
//закрываем файл
fclose($file);
//вызываем функцию shighlight()
return shighlight( $document);
}
?>
Работа функции сводится к открытию переданного в параметре $filename файла и передаче его содержимого ранее созданной функции shighlight().