Сделай Сам Свою Работу на 5

Модификаторы регулярных выражений





 

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

 

Таблица 11.3.1:

Модификатор Значение
i Включение режима case-insensitive, т.е. большие и маленькие буквы в выражении не различаются.
m Указывает на то, что текст, по которому ведется поиск, должен рассматриваться как состоящий из нескольких строк. По умолчанию механизм регулярных выражений рассматривает текст как одну строку вне зависимости от того, чем она является на самом деле. Соответственно метасимволы '^' и '$' указывают на начало и конец всего текста. Если же этот модификатор указан, то они будут указывать соответственно на начало и конец каждой строки текста.
s По умолчанию метасимвол '.' не включает в свое определение символ перевода строки. Т.е. для многострочного текста выражение /.+/ вернет только первую строку, а не весь текст, как ожидается. Указание этого модификатора снимает это ограничение.
U Делает все количественные метасимволы "не жадными" по умолчанию (про "жадность" количественных метасимволов см. выше)

 



 

Функции PHP для работы с регулярными выражениями

 

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

 

Preg_match()

 

int preg_match (string pattern, string subject [, array matches])

 

Эта функция предназначена для проверки того, совпадает ли заданная строка (subject) с заданным регулярным выражением (pattern). В качестве результата функция возвращает 1, если совпадения были найдены и 0, если нет. Если при вызове функции был задан необязательный параметр matches, то после работы функции ему будет присвоен массив, содержащий результаты поиска по заданному регулярному выражению. Заметьте, что вне зависимости от того, сколько именно совпадений было найдено при поиске – вам будет возвращено только первое совпадение. Рассмотрим пример того, как это работает (пример 11.4.1.1):



 

<?

$str = "123 234 345 456 567"; // Строка для поиска

$result = preg_match('/\d{3}/',$str,$found); // Производим поиск

echo "Matches: $result<br>"; // Выводим количество найденных совпадений

print_r($found); // Выводим результат поиска

?>

 

Результатом работы этой программы будет:

 

Matches: 1

Array

(

[0] => 123

)

 

Стоит заметить заметить, что реально функция preg_match() обнаружила в заданной строке 5 совпадений с заданным выражением, но вернула только первое из них. Казалось бы, что в этом случае было бы логичнее возвращать результаты поиска в виде строки, а не в виде массива, но это не так. Вспомните, что регулярное выражение может содержать в себе внутренние регулярные выражения, которые также возращают результат. А для того, чтобы вернуть результаты поиска по всем регулярным выражениям нам как раз и требуется массив. Для того, чтобы проиллюстрировать сказанное выше давайте немного изменим регулярное выражение и посмотрим на результат (пример 11.4.1.2):

 

<?

$str = "123 234 345 456 567";

// Теперь мы не просто ищем трехзначное число,

// но и получаем его среднюю цифру

$result = preg_match('/\d(\d)\d/',$str,$found);

echo "Matches: $result<br>";

print_r($found);

?>

 

Результат будет следующим:

 

Matches: 1

Array

(

[0] => 123

[1] => 2

)

Как видите – здесь присутствуют результаты поиска по всем имеющимся регулярным выражениям.

 

Preg_match_all()

 

int preg_match_all (string pattern, string subject, array matches [, int order])

 

Эта функция очень похожа на предыдущую и предназначена для тех же самых целей. Единственное её отличие от preg_match() состоит в том, что она осуществляет "глобальный" поиск в заданном тексте по заданному регулярному выражению и, соответственно, находит и возвращает все имеющиеся совпадения. Посмотрим, как отличается работа этой функции на том же самом примере (пример 11.4.2.1):



 

<?

$str = "123 234 345 456 567";

$result = preg_match_all('/\d{3}/',$str,$found);

echo "Matches: $result<br>";

print_r($found);

?>

 

Результат работы:

 

Matches: 5

Array

(

[0] => Array

(

[0] => 123

[1] => 234

[2] => 345

[3] => 456

[4] => 567

)

)

 

Как видите – здесь мы получили все найденные совпадения и их количество в качестве результата.

Необходимо обратить ваше внимание на дополнительный параметр, появившийся в этой функции по сравнению с preg_match(): order. Значение этого параметра определяет структуру выходного массива с найденными совпадениями. Его значение может быть одним из перечисленных ниже:

· PREG_PATTERN_ORDER – результаты поиска будут сгруппированы по номеру регулярного выражения, которое возвратило этот результат (это значение используется по умолчанию).

· PREG_SET_ORDER – результаты поиска будут сгруппированы по месту их нахождения в тексте

 

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

Сначала посмотрим на то, как выглядит результат при использовании PREG_PATTERN_ORDER (пример 11.4.2.2):

 

<?

$str = "123 234 345 456 567";

$order = PREG_PATTERN_ORDER;

$result = preg_match_all('/\d(\d)\d/',$str,$found,$order);

print_r($found);

?>

 

Результат:

 

Array

(

[0] => Array

(

[0] => 123

[1] => 234

[2] => 345

[3] => 456

[4] => 567

)

[1] => Array

(

[0] => 2

[1] => 3

[2] => 4

[3] => 5

[4] => 6

)

)

 

Как видите – массив результатов содержит внешние индексы, соответствующие номерам регулярных выражений, от которых получен результат (индекс 0 имеет основное регулярное выражение). По этим индексам в массиве расположены массивы, содержащие непосредственно найденную информацию, причем индекс в этом внутреннем массиве соответствует "порядковому номеру" данного фрагмента в исходном тексте.

Теперь попробуем то же самое, но с PREG_SET_ORDER (пример 11.4.2.3):

 

<?

$str = "123 234 345 456 567";

$order = PREG_SET_ORDER;

$result = preg_match_all('/\d(\d)\d/',$str,$found,$order);

print_r($found);

?>

 

Результат:

 

Array

(

[0] => Array

(

[0] => 123

[1] => 2

)

[1] => Array

(

[0] => 234

[1] => 3

)

[2] => Array

(

[0] => 345

[1] => 4

)

[3] => Array

(

[0] => 456

[1] => 5

)

[4] => Array

(

[0] => 567

[1] => 6

)

)

 

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

 

 

Preg_replace()

 

mixed preg_replace (mixed pattern, mixed replacement, mixed subject [, int limit])

 

Эта функция позволяет произвести замену текста по регулярному выражению. Как и в предыдущих функциях, здесь производится поиск по регулярному выражению pattern в тексте subject, и каждый найденный фрагмент текста заменяется на текст, заданный в replacement. Задание необязятельного параметра limit позволит ограничить количество заменяемых фрагментов в тексте.

Например, нам необходимо "сжать" текст, убрав из него все лишние пробелы и символы перевода строки (пример 11.4.3.1):

 

<?

$text = "there is\t\n\t\t some text \n \t just \n\n\n for test";

echo "<b>Перед заменой:</b>\n$text\n\n";

$text = preg_replace("/(\n \s{2,})/"," ",$text);

echo "<b>После замены:</b>\n$text";

?>

 

Результат:

Перед заменой:

 

there is

some text

just

 

 

for test

 

После замены:

 

there is some text just for test

 

Однако основная прелесть этой функции, которая и придает ей всю её мощь – это тот факт, что вы можете ссылаться на результаты поиска при генерации замещающего текста. В качесте примера покажем, как можно очень быстро и элегантно решить задачу, которая возникает достаточно часто – конвертация дат из одного формата в другой. Как вы знаете, на западе обычно используется формат mm/dd/yyyy, тогда как у нас обычно - dd.mm.yyyy. Следующий пример осуществляет конвертацию дат между этими форматами в заданном тексте (пример 11.4.3.2):

 

<?

$text = 'Today is 11/16/2001';

$text=preg_replace("/(\d{2})\/(\d{2})\/(\d{4})/","\\2.\\1.\\3",$text);

echo $text;

?>

 

Результат:

 

Today is 16.11.2001

 

Обратите внимание на текст, используемый для замены. В нём использованы т.н. backreferences, т.е. ссылки на найденный ранее текст. Всего таких ссылок может быть не более 100 с номерами от 0 до 99 (соответственно в тексте они выглядят как \0, \1, \2 ... \99). Backreference с номером 0 будет заменена на весь найденный текст, \1 - на текст, найденный первым внутренним регулярным выражением, \2 - вторым и т.д. Номера внутренним регулярным выражениям присваиваются по мере их находжения в тексте, т.е. слева-направо. В нашем случае \1 - это месяц, \2 - день, \3 - год.

Помимо стандартного синтаксиса регулярных выражений, в PHP, совместно с функцией preg_replace() используется еще один дополнительный модификатор – 'e'. Его использование заставляет PHP рассматривать текст замены не как текст, а как PHP код, что дает возможность еще больше расширить сферу применения этой функции в вашем коде. Следующий пример демонстрирует использование этого модификатора – он производит замену всех целых десятичных чисел в тексте на их шестнадцатиричные эквиваленты (пример 11.4.3.3):

 

<?

$text = "123 234 345 456 567";

$text = preg_replace("/\d+/e","'0x'.dechex('\\0')",$text);

print_r($text);

?>

 

Результат:

 

0x7b 0xea 0x159 0x1c8 0x237

 

Функция preg_replace() также умеет работать с массивами регулярных выражений. Т.е. это позволит вам осуществить поиск и замену сразу по множеству условий. В качестве примера приведём фрагмент кода, описанный в PHP Manual и осуществляющий конвертацию HTML документа в текст при помощи всего лишь одного вызова preg_replace() (пример 11.4.3.4):

 

// $document should contain an HTML document.

// This will remove HTML tags, javascript sections

// and white space. It will also convert some

// common HTML entities to their text equivalent.

 

$search = array ("'<script[^>]*?>.*?</script>'si", // Strip out javascript

"'<[\/\!]*?[^<>]*?>'si", // Strip out html tags

"'([\r\n])[\s]+'", // Strip out white space

"'&(quot #34);'i", // Replace html entities

"'&(amp #38);'i",

"'&(lt #60);'i",

"'&(gt #62);'i",

"'&(nbsp #160);'i",

"'&(iexcl #161);'i",

"'&(cent #162);'i",

"'&(pound #163);'i",

"'&(copy #169);'i",

"'&#(\d+);'e"); // evaluate as php

 

$replace = array ("",

"",

"\\1",

"\"",

"&",

"<",

">",

" ",

chr(161),

chr(162),

chr(163),

chr(169),

"chr(\\1)");

 

$text = preg_replace ($search, $replace, $document);

 

Preg_replace_callback()

 

mixed preg_replace_callback (mixed pattern, mixed callback, mixed subject [, int limit])

 

Эта функция является расширенной версией функции preg_replace(). Единственным отличием её от preg_replace() является то, что в качестве текста для замены в ней задается не сам текст, а имя функции, которая будет производить обработку найденного текста и возвращать замещающий текст. Т.е. с использованием этой функции мощь инструментария PHP по обработке текста становится поистине безграничной. В качестве примера приведём фрагмент кода, который выполняет работу, аналогичную той, что производится механизмом сессий в PHP: добавление дополнительного аргумента (идентификатора сессии) к каждой ссылке внутри HTML документа (пример 11.4.7.1).

 

<?

// Список тегов и аттрибутов, к котроым необходимо

// добавить дополнительный параметр.

// Формат строки:

// <имя тега>[ <имя аттрибута>]+

// Т.е. сначала идет имя тега, а затем, через пробел,

// имена одного или нескольких аттрибутов.

$tagsList = array(

'a href',

'area href',

'frame src',

'input src',

'img src',

'form action'

);

// Идентификатор сессии

$sid = 12345;

// HTML документ для обработки. Здесь, в качестве примера

// мы берем его из внешнего файла, но вообще-то метод

// получения исходного документа может быть различным.

$document = join('',file('document.html'));

// Начинаем обработку всех тегов, указанных в массиве $tagsList

foreach($tagsList as $tag)

{

// Разделяем список аттрибутов на составляющие

$attrs = explode(' ',$tag);

// Получаем имя тега (в массиве $attrs остается лишь список аттрибутов)

$tag = array_shift($attrs);

// Выполняем "патч" всех имеющихся в документе ссылок, содержащихся

// в каждом из аттрибутов текущего тега

foreach($attrs as $attr)

$document = preg_replace_callback("/<".$tag.".+?".$attr."=[\'\"](.+?)[\'\"]/si",

'callback',$document);

};

// Выводим документ и выходим

echo $document;

exit();

// Эта функция будет вызываться для каждой найденной

// ссылки в тексте HTML документа.

// На входе она получает результат поиска (массив,

// аналогичный возвращаемому функцией preg_match()).

// На выходе из функции должна быть строка с текстом замены.

function callback($data)

{

// Регулярное выражение, использованное для поиска находит полные

// HTML теги, содержащие аттрибуты, в которых могут находиться

// URL адреса. Поскольку текст, возвращаемый данной функцией будет

// использован для замещения всего найденного фрагмента текста -

// нам необходимо взять полный текст, чтобы не потерять его при

// дальнейшей обработке. Он будет возвращен без изменений, если

// окажется, что аттрибут не содержит URL адреса.

$href = $data[0];

// Используем функцию PHP для разбора URL адреса на составляющие.

// В качестве "исходного материала" передаем содержимое интересующего

// нас аттрибута, найденного внутренним регулярным выражением.

// Подробнее о том, что возвращает эта функция см. PHP Manual.

$parts = parse_url($data[1]);

// Мы должны добвлять идентификатор сессии только к ссылкам, которые

// являются "локальными" для данного сайта. Т.е. мы не должны обрабатывать:

// - полные URL адреса (<a href="http://www.php.net/">)

// - указатели на "якоря" внутри страницы (<a href="#part2">)

if ((!isset($parts['scheme'])) && // Если URL содержит идентификатор

(!isset($parts['host'])) && // протокола или имя домена - это

// полный URL адрес.

(substr($data[1],0,1)!='#')) // Если URL начинается с символа '#'

// то это ссылка на "якорь" внутри страницы

{

// Берем путь к странице, указанный в URL и добавляем разделитель для параметров

// потому что нам необходимо будет добавить по крайней мере 1 параметр

$href = $parts['path'].'?';

// Если в этом URL уже были какие-либо параметры - добавляем их и добавляем

// разделитель. Заметьте, что в качестве разделителя используется &amp;, а не &,

// это позволяет нам добиться совместимости с XHTML.

if (isset($parts['query']))

$href .= $parts['query'].'&amp;';

// Добавляем наш собственный параметр - идентификатор сессии

$href .= 'sid='.$GLOBALS['sid'];

// Если в оригинальном URL была ссылка на фрагмент документа - возвращаем ее

// на место.

if (isset($parts['fragment']))

$href .= '#'.$parts['fragment'];

// "Вставляем" новый URL на место того, который был там раньше

$href = str_replace($data[1],$href,$data[0]);

};

// Возвращаем результат

return($href);

};

?>

 

Пример может показаться немного громоздким, но это исключительно из-за обилия комментариев.

 

Preg_split()

 

array preg_split (string pattern, string subject [, int limit [, int flags]])

 

Данная функция выполняет действие, аналогичное функциям split() и explode() – разбивает строку на части по какому-либо признаку и возвращает массив, содержащий части строки. Однако её возможности по заданию правил разбиения больше, чем у этих функций, потому что в её основе лежит механизм регулярных выражений. Если говорить более конкретно, то строка subject разбивается на части по разделителю, заданному регулярным выражением pattern. При этом количество фрагментов может быть ограничего необязятельным параметром limit. Кроме того эта функция поддерживает необязательный параметр flags, который позволяет в некоторой степени контролировать процесс разбиения строки.

Параметр flags может принимать следующие значения (или их комбинации с использованием знака '|'):

· PREG_SPLIT_NO_EMPTY – возвращать только непустые части строк, полученные в результате разбиения.

· PREG_SPLIT_DELIM_CAPTURE – возвращать также результаты поиска по внутренним регулярным выражениям.

 

Рассмотрим пару примеров. Для начала – выражение, которое разбивает произвольный текст на отдельные слова (пример 11.4.5.1):

 

<?

$text = join('',file('my_text.txt'));

$words = preg_split("/\s+/s",$text);

print_r($words);

?>

 

Как видите – мы получаем содержимое файла 'my_text.txt' в виде строки, разбиваем его на отдельные слова и выводим содержимое массива слов, чтобы убедиться, что все работает правильно.

Ещё один пример производит разбиение заданного слова на буквы (он описан в PHP Manual) (пример 11.4.5.2):

 

 

<?

$str = 'string';

$chars = preg_split('//',$str,-1,PREG_SPLIT_NO_EMPTY);

print_r($chars);

// Значение -1 для параметра limit означает отсутствие лимита.

?>

 

Preg_quote()

 

string preg_quote (string str [, string delimiter])

 

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

 

. \ + * ? [ ^ ] $ ( ) { } = ! < > | :

 

Все эти символы, встречающиеся в строке будут "отквочены" путем добавления символа '\' непосредственно перед каждым из них. Модифицированная таким образом строка будет возвращены в качестве результата.

Эта фцнкция также имеет необязательный параметр delimiter. Если этот параметр задан, то символ, переданный в качестве этого параметра тоже будет "отквочен" данной функцией.

 

Preg_grep()

 

array preg_grep (string pattern, array input)

 

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

 

Файл data.txt:

 

abc

php4

 

Код:

 

<?

// Считываем содержимое файла в массив

$data = file('data.txt');

// Получаем массив, содержащий цифровую информацию

$numbers = preg_grep("/\d+/",$data);

// Выводим результат работы

print_r($numbers);

?>

 

Результат:

 

Array

(

[0] => 123

[2] => php4

)

 

Как видите – мы получили все строки, содержащие цифры. Если же нам, например нужно получить только цифры - то выражение необходимо немного изменить:

 

/^\s*\d+\s*$/

 

 

 








Не нашли, что искали? Воспользуйтесь поиском по сайту:



©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.