Позитивный и негативный просмотр

Иногда нужно решить задачу такого типа: найти строку 'aaa' и заменить ее на '!', но только если перед 'aaa' стоит 'x' (при этом 'x' не заменять).

Если мы попытаемся решить задачу 'в лоб', то у нас ничего не выйдет:

<?php
	echo preg_replace('#xaaa#', '!', 'xaaa baaa'); //выведет '! baaa', а хотели 'x! baaa'
?>

Нужен способ сказать, что 'x' не следует заменять. Делается это с помощью специальных скобок (?<= ), которые просто смотрят, но не забирают с собой:

<?php
	echo preg_replace('#(?<=x)aaa#', '!', 'xaaa baaa'); //выведет 'x! baaa'
?>

Скобки (?<= ) называются позитивный просмотр назад. Позитивный - так как 'x' (в нашем случае) должен быть - только тогда произойдет замена. Есть и негативный просмотр назад - (?<! ) - он, наоборот, говорит, что чего-то должно не быть:

<?php
	//Если перед 'aaa' стоит НЕ 'x', тогда заменим на '!':
	echo preg_replace('#(?<!x)aaa#', '!', 'xaaa baaa'); //выведет 'xaaa b!'
?>

Аналогичные операции выполняют позитивный просмотр вперед (?= ) и негативный просмотр вперед (?! ):

<?php
	//Если после 'aaa' стоит  'x', тогда заменим на '!':
	echo preg_replace('#aaa(?=x)#', '!', 'aaax aaab'); //выведет '!x aaab'
?>
<?php
	//Если после 'aaa' стоит НЕ 'x', тогда заменим на '!':
	echo preg_replace('#aaa(?!x)#', '!', 'aaax aaab'); //выведет 'aaax !b'
?>

Функция preg_replace_callback

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

В этом нам поможет функция preg_replace_callback(регулярка, 'название функции', где менять), которая похожа на preg_replace, но вторым параметром принимает название функции, которая вернет то, на что заменять.

Внутри этой функции будут доступны карманы. Каким образом - смотрите в примере:

Пример

Задача: даны строки вида '2+3=', нужно заменить их на тоже самое, но после равно - результат сложения '2+3=5'. Для начала поэкспериментируем:

<?php
	echo preg_replace_callback('#(\d+)\+(\d+)=#', 'sum', '2+3=');
 	function sum($matches)
	{
		var_dump($matches);
 	}
?>

Функция var_dump выведет массив [0=>'2+3', 1=>'2', 2=>'3'] – то есть там лежит найденная строка и карманы. Название переменной не обязательно делать $matches, оно может быть любым - главное, чтобы эта переменная стояла параметром функции, которую мы вызываем (в нашем случае это sum).

Мы теперь знаем как получить доступ к карманам, давайте решим задачу до конца:

<?php
	echo preg_replace_callback('#(\d+)\+(\d+)=#', 'sum', '2+3=');
 	function sum($matches)
	{
		$sum = $matches[1] + $matches[2]; //получаем сумму 2+3=5
		$result = $matches[0].$sum; //$matches[0] - это исходная строка '2+3='
		return $result;
	}
	//В результате выведет '2+3=5'
?>

Еще функции для работы с регулярками

preg_quote

preg_quote(строка, [доп. символы]) - экранирует спец. символы регулярных выражений в строке. Зачем это нужно? Например, вы формируете регулярку динамически '#'.$var.'#' - и хотите быть уверенными, что туда не попадут спецсимволы. Иногда полезно.

Второй параметр нужен для добавления своих символов для экранировки.

preg_grep

preg_grep(регулярка, массив) – принимает массив, а возвращает массив только с теми элементами, которые подпадают под регулярку.

preg_split

preg_split - разбивает строку в массив по регулярному выражению (типа explode, только с регуляркой).

Модификаторы

Модификаторы - это команды, которые записываются после второго ограничителя ('#.+#iu' – 'iu' – модификаторы). Они позволяют изменять свойства регулярных выражений.

Давайте посмотрим на самые полезные модификаторы:

Модификатор x

x – регулярка перестанет учитывать пробелы и можно будет ставить комментарии после решетки # (однострочные):

<?php
	//С комментариями намного понятнее (но длиннее):
	echo preg_replace('&
		.+? #любой символ один или более раз
		a #потом буква a
	&x', '!', 'строка');
?>

Внимание: в этом случае решетки в качестве ограничителей использовать нельзя, поэтому здесь стоят амперсанды.

Модификаторы m и s

Пока мы не обращали внимание на то, что наши регулярки могут обрабатывать не только однострочные строки, но и многострочные (те, где есть enter-ы - переводы строк).

<?php
	$str = '
		первая подстрока
		вторая подстрока
	';
?>

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

Многострочный режим явно задается с помощью модификатора m, а однострочный - с помощью модификатора s.

Давайте посмотрим разницу между этими режимами:

Многострочный:

Шляпка ^ соответствует началу каждой подстроки, а $ - концу:

<?php
	$str = '
		^первая подстрока$
		^вторая подстрока$
	';
?>

Вместо ^ для начала всей строки следует использовать \A, а вместо $ для конца всей строки - \z.

Точка совпадает с любым символом, за исключением перевода строки (точнее она не совпадает со \n, а со \r совпадает!).

Однострочный:

Шляпка ^ соответствует началу всей строки, а $ - концу:

<?php
	$str = '^
		первая подстрока
		вторая подстрока
	$';
?>

Точка совпадает с любым символом.

Внимание!!! По умолчанию функции поиска preg_match и preg_match_all работают в многострочном режиме (будто добавлен модификатор m), а поиска и замены preg_replace - в однострочном (будто добавлен модификатор s)!

Исправляйте добавлением соответствующего модификатора (при необходимости).

Модификатор i

i – игнорирование регистра, '#[a-z]#i' - такое теперь найдет и заглавные буквы.

Модификатор U

U – нежадный поиск, все операторы повторений станут нежадными, а '?', наоборот, будет добавлять им жадности.

Модификатор u

u – корректная работа с utf-8, ставьте его, чтобы не было проблем с кириллицей.

Модификатор X

X – если его поставить, то экранировка обычного символа приведет к ошибке. Без него - обычные символы можно экранировать, они все равно будут обозначать сами себя (исключение: цифры, они станут карманами).

Модификатор e

e – позволяет выполнить php код после вставки, работает только в preg_replace. Не всегда работает правильно (имеет проблему с кавычками), поэтому лучше пользоваться preg_replace_callback. Подробное описание см. в книге 'PHP 5 в подлиннике' Д. Котеров, А. Костарев, глава про регулярные выражения, подпункт про модификаторы.

Порядок модификаторов значения не имеет.

Все модификаторы описаны тут.