Реклама в журнале

Регулярные выражения 2

Источник: http://webhowto.ru/

Авторство: Neoweb
http://phpweb.ru

Рассмотрим функции для работы с регулярными выражениями формата PCRE.
int preg_match ( string pattern, string subject [, array matches [, int flags]]) - служит для сопоставления строки subject, регулярному выражению pattern. Функция возвращает 1 или 0, в зависимости от того, найдено совпадение, или нет. Если задан необязательный параметр matches, то создаётся массив, содержащий результаты поиска по регулярному выражению. Обратите внимание, что, если даже совпадений было несколько, функция завершает свою работу сразу после того, как обнаружит первое совпадение. Пример:

<?
$c=preg_match("/\w\d{2}/","k22 007 T34 bx z13", $arr);
echo $c;
?>

Возвращает 1. Третий параметр можно было и не указывать. Массив $arr, будет состоять всего из одного элемента. $arr[0]="k22". Возникает естественный вопрос: зачем возвращать совпадение в виде массива, если он (массив) будет всегда состоять только из одного элемента? Оказывается это не так. Вспомните первую часть этой статьи. Там я рассказывал про такой спецсимвол, как круглые скобки. Если в регулярном выражении встречаются круглые скобки, то парсер рассматривает их содержимое, как отдельное выражение. Естественно, что этих скобок может встречаться любое необходимое количество. Для этого preg_match и создает массив, чтобы вернуть результат поиска по всем регулярным выражениям. Рассмотрим всё на примере:

<?php
$strin="nex z1c dyt b2k kid d1l d1l d1l";
preg_match("/\w(\d)(\w)/",$strin,$arr);
print_r($arr);
?>

Возможно функция bool print_r (mixed expression) является для Вас новой (я о ней ещё не рассказывал). Используется она довольно редко, но в данном случае удобна. Тип параметра, который может быть передан функции: строка, любое число, массив, объект. Для числа и строки, она не делает ничего интересного, просто выводит их, как echo или print. Если же передать ей массив (особенно актуально для многомерного массива), то он будет отображен в удобном виде (наглядно).

Вернёмся к нашему примеру. Выражение будет соответствовать любой строке, которая состоит из 3 символов (два любых символа и цифра между ними). Массив $arr выглядит так: Array ([0] => z1c [1] => 1 [2] => c ). Нулевой элемент - часть строки, которая соответствует полному регулярному выражению, а последующие - его фрагментам, т.е. частям выражения, заключенным в круглые скобки.

int preg_match_all ( string pattern, string subject, array matches [, int flags]) - делает, то же самое, что и предыдущая функция, только поиск ведет не до первого совпадения, а глобально. Пускай нужно выделить из текста все числа типа float:

<? $strin="pi=3.14 g=9.8 r=7.31 ";
preg_match_all("/(\d+)\.(\d+)/",$strin,$arr);
print_r($arr);
?>

Результат: Array ( [0] => Array ( [0] => 3.14 [1] => 9.8 [2] => 7.31 ) [1] => Array ( [0] => 3 [1] => 9 [2] => 7 ) [2] => Array ( [0] => 14 [1] => 8 [2] => 31 ) ). Результатом работы функции является массив, каждый элемент которого, в свою очередь, тоже имеет тип массива. Первый "подмассив" состоит из частей строки, которые соответствуют всему регулярному выражению. Второй содержит элементы, соответствующие целым частям чисел, а третий - вещественным. Такой порядок можно и изменить, указав третий параметр int flags. Он может принимать следующие значения: PREG_PATTERN_ORDER -(используется по умолчанию) если поиск производится таким образом, то дело обстоит так же, как в предыдущем примере. Нулевой элемент array matches является массивом, в котором находятся подстроки с полным соответствием, первый - массив с соответствием по первой части выражения и т.д. PREG_SET_ORDER :

<? $strin="pi=3.14 g=9.8 r=7.31 ";
preg_match_all("/(\d+)\.(\d+)/",
$strin,$arr, PREG_SET_ORDER);
print_r($arr);
?>

Результат: Array ( [0] => Array ( [0] => 3.14 [1] => 3 [2] => 14 ) [1] => Array ( [0] => 9.8 [1] => 9 [2] => 8 ) [2] => Array ( [0] => 7.31 [1] => 7 [2] => 31 ) ) Результаты поиска заносятся в массив array matches по месту их нахождения в тексте. Пусть, дана строка, в которой некоторые слова выделены каким - либо парным тэгом. $str="I love <i>PHP</i>. It is <b>cool</b>"; Наша задача - получить выделенную подстроку, и узнать, каким тэгом она обрамлена. Регулярное выражение не может выглядеть так: ~<(\w+)>(.*)</(\w)>~, т.к. оно будет соответствовать и <i>PHP</b> и <pre>PHP</i> и т.д. Нам же нужно соответствие, только если тэги парные. Выход из ситуации:


preg_match_all( "~<(\w+)>(.*)< \\1>~",$str,$arr); (в качестве разделителя использована ~, т.к. / используется в самом регулярном выражении) \1 -называется карманом (в регулярном выражении \ удваивается, для того, чтобы парсер рассматривал его именно, как \, а не как спецсимвол). Карман - специальная ссылка, которая указывает на найденный ранее текст. Нумеруются карманы так:\0, \1, \2, \3 и т.д. (начиная с версии PHP 4.0.4, нумерация может быть и такой: $0,$1,$2,$3). При этом нужно не забывать ставить \ перед спецсимволом $.) Максимальное количество карманов - 100, т.е. от \\0 до \\99. Нумерация проходит по открывающей скобке - слева на право: (на это будет указывать первый карман (второй (3))(4)). Нулевой карман будет заменен всем найденным текстом. При просмотре выражения ~<(\w+)>(.*)</\\1>~ парсер присвоит значение тэга первому карману, и заменит \\1 на это значение. В результате мы получим парный тэг. Во втором кармане будет записано значение подстроки между тэгами.

<?php $str="I love <i>PHP</i>. It is <b>cool</b>";
preg_match_all( "~<(\w+)>(.*)</\\1>~",$str,$arr);
print_r($arr);
echo "Слово  ".$arr[2][0]."  выделено тэгом  ".$arr[1][0]; 
echo "<br>Слово  ".$arr[2][1]."  выделено тэгом
 ".$arr[1][1];
?>

Результат: Array ( [0] => Array ( [0] => PHP [1] => cool ) [1] => Array ( [0] => i [1] => b ) [2] => Array ( [0] => PHP [1] => cool ) ) Слово PHP выделено тэгом i Слово cool выделено тэгом b Позже мы ещё поговорим о карманах.

mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit]) - функция производит поиск с заменой по регулярному выражению. Одна из самых интересных и часто используемых функций. Поиск производится в тексте subject по регулярному выражению pattern. Каждое соответствие заменяется текстом, заданным в replacement. Если совпадения были найдены, функция возвращает текст с заменами, в противном случае - текст без изменений. Если необходимо произвести замены сразу по нескольким регулярным выражениям, то в качестве параметров pattern и replacement могут быть переданы массивы. Совпадение по первому регулярному выражению из массива pattern будет изменено первой строкой массива replacement, второе выражение - второй строкой и т.д. Однако так будет, только если элементы этих массивов добавлялись в них по очереди (нулевой элемент, первый и т.д.). В общем случае замена происходит по порядку добавления в массив. Пример:

<?php
$subject="C, Java и Perl";
$pattern[0]="/C/";
$pattern[1]="/Java/";
$pattern[2]="/Perl/";
$replacement[2]="TCL";
$replacement[1]="PHP";
$replacement[0]="Ocaml";
echo preg_replace($pattern,$replacement,$subject);
?>

Результат: TCL, PHP и Ocaml. Хотя, казалось бы, нужно было ожидать: Ocaml, PHP и TCL. Если для Вас важно, чтобы замена проходила в соответствии с ключами массива, то предварительно примените функцию ksort(), которая отсортирует массивы $pattern и $replacement по ключу. Вот ещё один стандартный пример, который конвертирует дату из формата дд/мм/гггг в формат дд.мм.гггг.

<?php $text = 'Сегодня 27/06/2003';
$text = preg_replace("/(\d{2})\/(\d{2})\/(\{4})/", 
"\\2.\\1.\\3",$text);
echo $text; ?>

Следующие два примера более интересны и чаще используются: 1)Преобразование e-mail адреса. Ищет в тексте строки вида: usermail@userhost и меняет их на HTML ссылки <a href=" usermail@userhost "> usermail@userhost </a>.

<?php
$text = 'E-mail Васи - va-sya@mail.ru. И ещё один - 
pupkin@mail.fbi.gov .';
echo $text;
$text=preg_replace("/(([\w-.]+)@(\w+)(\\.[\w-]+)*)/",
'<a href="mailto:$0">$0</a>',$text);
echo $text;
?>

С помощью этого регулярного выражения вы сможете проверить почтовый адрес на правильность (например, при проверке соответствующего поля какой-то формы):

<?php
if(!preg_match("/([\w-.]+)@(\w+)(\\.[\w-]+)*/")), $email)
echo "$email не является адресом электронной почты";
?>

Так же, как только что мы преобразовывали, e-mail адреса, можно поступить и с гиперссылками. Заменим подстроки типа протокол://URL на <a href=" протокол://URL "> протокол://URL </a>.

Напоследок, краткий обзор ещё нескольких полезных функций.

string preg_quote ( string str [, string delimiter]) - расставляет в строке str символ '\' перед всеми спецсимволами регулярных выражений (. \\ + * ? [ ^ ] $ ( ) { } = ! < > | :), для отмены их действия, и возвращает видоизменённую строку. Если задан необязательный параметр delimiter, то перед этим символом также будет проставлен '\'. Функция полезна для предварительной обработки строки, которая будет использоваться, в регулярном выражении, для поиска совпадений по какому-либо тексту (в случае если она содержит спецсимволы).

array preg_grep (string pattern, array input). Ищет совпадения в массиве array input по регулярному выражению string pattern и возвращает массив, состоящий из элементов, в которых совпадения были найдены. Пример:

<?php $str=array('this is php(perl) var $p',
'this is some text','$h','@3');
echo $str[0]; $regexp='/\$[A-Za-z_]+/';
$output=preg_grep($regexp,$str); print_r($output);
?>

На этом я заканчиваю рассказ о регулярных выражениях. В статье получилось довольно мало примеров, но к регулярным выражениям (к их практическому применению) я буду возвращаться ещё очень часто в следующих статьях. А пока осмыслите вышесказанное, и потренируйтесь в написании рег. выражений. Если что-то не получается, пишите мне, всегда буду рад помочь.


Играйте и выигрывайте! Интернет лотерея iLoto.net
Реклама в журнале

Copyright © <LMTH>. Все материалы являются собственностью их авторов.
При перепечатывании ссылка на http://www.magaz.org/ как на источник
информации обязательна. Правила использования материалов журнала