Мини профильНавигацияПопулярный материалПользователи онлайнАрхив материалаДрузья |
Регулярные выражения в PHP Регулярные выражения разрезает блоки информации по определённым шаблонам. Они сопровождаются огромным арсеналом инструментов. Сегодня мы рассмотрим некоторые продвинутые техники, которые вы сможете применить в ваших проектах. preg_match("/^(1[-\s.])?(\()?\d{3}(?(2)\))[-\s.]?\d{3}[-\s.]?\d{4}$/",$number) Пример регулярного выражения: preg_match("/^ (1[-\s.])? # выборочно '1-', '1.' or '1' ( \( )? # выборочно: открывающаяся скобка \d{3} # код (?(2) \) ) # если была открыта круглая скобка, закрыть [-\s.]? # далее '-' или '.' или пробел \d{3} # первые 3 цифры [-\s.]? # далее '-' или '.' или пробел \d{4} # последние 4 цифры $/x",$number); Хитрость заключается в символе “\x” в конце выражения. Это позволяет игнорировать пробелы (исключение: экранированные пробелы при помощи \s) в самом выражении для того, чтобы мы могли использовать комментарии (начинающиеся с # и заканчивающиеся перед переходом на новую строку); Использование функций обратного вызова В PHP существует функция preg_replace_callback(), которая используется для добавления функций обратного вызова к регулярным выражениям. Иногда возникает задача, когда нужно произвести нескольких замен в тексте. Если использовать функции preg_replace() или str_replace() для каждого шаблона, строка будет обрабатываться несколько раз. Пример замены в шаблоне email: $template = "Здравствуйте, [first_name] [last_name], Спасибо за покупку [product_name] в магазине [store_name]. Конечная цена [product_price] плюс [ship_price] за доставку. Вы можете ожидать посылку в течении [ship_days_min], [ship_days_max] рабочих дней. С уважением, [store_manager_name]"; // предположим что в массиве $data данные, которые нужно вставить вместо маркеров // такие как $data['first_name'] $data['product_price'] и т.д. $template = str_replace("[first_name]",$data['first_name'],$template); $template = str_replace("[last_name]",$data['last_name'],$template); $template = str_replace("[store_name]",$data['store_name'],$template); $template = str_replace("[product_name]",$data['product_name'],$template); $template = str_replace("[product_price]",$data['product_price'],$template); $template = str_replace("[ship_price]",$data['ship_price'],$template); $template = str_replace("[ship_days_min]",$data['ship_days_min'],$template); $template = str_replace("[ship_days_max]",$data['ship_days_max'],$template); $template = str_replace("[store_manager_name]",$data['store_manager_name'],$template); // это можно сделать и в цикле, // но лучше избежать столького количества итераций Заметим, что любой из “маркеров”, представленных в выражении выше, заключён в квадратные скобки. Мы можем выследить их и заменить при помощи функции обратного вызова. Вот так мы и поступим: // my_callback() будет вызываться каждый раз, когда будут найдены скобки $template = ppreg_replace_callback('/\[(.*)\]/','my_callback',$template); function my_callback($matches) { // $matches[1] теперь содержит строку, которая находилась между скобок if (isset($data[$matches[1]])) { // вернуть заменённую строку return $data[$matches[1]]; } else { return $matches[0]; } } Теперь строка используется только единожды. “Сетка” против “Не сетки” Перед тем, как объясниться, я продемонстрирую пример. Предположим, что нам необходимо найти угловые скобки html элементов: $html = 'Привет <a href="http://arts-up.ru">Мир!</a>'; if (preg_match_all('/<a.*>.*<\/a>/',$html,$matches)) { print_r($matches); } Результат будет следующим: /* на выходе: Array ( [0] => Array ( [0] => <a href="http://arts-up.ru">Мир!</a> ) ) */ Добавим второй тег: $html = '<a href="http://arts-up.ru">Привет</a> <a href="http://arts-up.ru">Мир!</a>'; if (preg_match_all('/<a.*>.*<\/a>/',$html,$matches)) { print_r($matches); } /* на выходе: Array ( [0] => Array ( [0] => <a href="http://arts-up.ru">Hello</a> [1] => <a href="http://arts-up.ru">World!</a> ) ) */ Всё это работает благодаря тому, что ссылки находятся на разных строках. Если поместить их на одной, данный скрипт не сработает т.к. регулярные выражения обрабатывают по строкам. $html = '<a href="http://arts-up.ru">Hello</a> <a href="http://arts-up.ru">World!</a>'; if (preg_match_all('/<a.*>.*<\/a>/',$html,$matches)) { print_r($matches); } /* на выходе: Array ( [0] => Array ( [0] => <a href="http://arts-up.ru">Привет</a> <a href="http://arts-up.ru">Мир!</a> ) ) */ На этот раз регулярное выражение нашло только первый открывающийся и закрывающийся тег. В народе техника приведённая выше называется “Сетка” Если в регулярное выражение мы добавим (.*?) то эта техника снова заработает и в случае строки без переноса: $html = '<a href="http://arts-up.ru">Привет</a> <a href="http://arts-up.ru">Мир!</a>'; // заметьте ? if (preg_match_all('/<a.*?>.*?<\/a>/',$html,$matches)) { print_r($matches); } /* на выходе: Array ( [0] => Array ( [0] => <a href="http://arts-up.ru">Hello</a> [1] => <a href="http://arts-up.ru">World!</a> ) ) */ Теперь всё работает нормально. Предыдущие и последующие выражения И снова начнём с примера. Данное регулярное выражение ищет строку foo за которой следует строка bar: $pattern = '/foo(?=bar)/'; preg_match($pattern,'Hello foo'); // false preg_match($pattern,'Hello foobar'); // true А теперь наоборот: $pattern = '/foo(?!bar)/'; preg_match($pattern,'Hello foo'); // true preg_match($pattern,'Hello foobar'); // false preg_match($pattern,'Hello foobaz'); // true Поиск последующего выражения происходит до того, как произошло нахождение предыдущего выражения. Используйте ?< для позитивных выражений, _ Ещё пример: $pattern = '/(?<!foo)bar/'; preg_match($pattern,'Hello bar'); // true preg_match($pattern,'Hello foobar'); // false preg_match($pattern,'Hello bazbar'); // true Шаблоны для условий (If-Then-Else) Формат таких выражений выглядит следующим образом:(?(condition)true-pattern|false-pattern) или (?(condition)true-pattern) В качестве условия может быть вставлено число. Приведу более распространённый пример для нахождения всё тех же открывающихся и закрывающихся скобок: $pattern = '/^(<)?[a-z]+(?(1)>)$/'; preg_match($pattern, ''); // true preg_match($pattern, ''); // false preg_match($pattern, 'hello'); // true Это выражение работает следующим образом: закрывающийся тег ищется только при том условии, если был найден открывающийся тег. Можно писать и такие выражения: // начинаем с поиска 'q', // если таковых символов нет ищем 'f' $pattern = '/^(?(?=q)qu|f)/'; preg_match($pattern, 'quake'); // true preg_match($pattern, 'qwerty'); // false preg_match($pattern, 'foo'); // true preg_match($pattern, 'bar'); // false Фильтрование Существуют различные причины для фильтрации входных данных при разработке веб-приложений. Мы фильтруем данные перед вставкой в базу или при выводе их в браузер. Аналогичным образом, перед примирением регулярного выражения строку нужно отфильтровать. В PHP существует функция preg_quote() специально для этих целей. В следующем примере мы используем строку, которая содержит символ (*): $word = '*мир*'; e$text = 'Привет *мир*!'; preg_match('/'.$word.'/', $text); // вызовет warning preg_match('/'.preg_quote($word).'/', $text); // tru Того же самого эффекта может добиться, заключив строку между \Q и \E. $word = '*мир*'; $text = 'Привет *мир*!'; preg_match('/\Q'.$word.'\E/', $text); // true К слову сказать, второй пример не всегда не очень хорош с точки зрения безопасности. В самой строке может находится символ \E. Подшаблоны Подшаблоны, записанные в круглые скобки заключают свой результат в массив для дальнейшего использования. Начнём с небольшого примера: preg_match('/(f.*)(b.*)/', 'Hello foobar', $matches); echo "f* => " . $matches[1]; // prints 'f* => foo' echo "b* => " . $matches[2]; // prints 'b* => bar' Теперь произведём небольшое изменение, добавив (H.*) в начало (часто распространённая ловушка). Нарушилась последовательность индексов: preg_match('/(H.*) (f.*)(b.*)/', 'Hello foobar', $matches); echo "f* => " . $matches[1]; // prints 'f* => Hello' echo "b* => " . $matches[2]; // prints 'b* => foo' Теперь порядок элементов в массиве немного изменился. Исправим ситуацию для того, чтобы скрипт работал корректно: preg_match('/(?:H.*) (f.*)(b.*)/', 'Hello foobar', $matches); echo "f* => " . $matches[1]; // prints 'f* => foo' echo "b* => " . $matches[2]; // prints 'b* => bar' Добавив ‘?:’, мы сообщаем, что не добавляем этот элемент в массив. Так что последовательность индексов не нарушится. Именованные подшаблоны Существует еще один метод для предотвращения ловушек, как в предыдущем примере. Мы можем каждому подшаблону дать своё имя, а потом ссылаться на них. Формат: (? Ppattern) Перепишем прошлые пример: preg_match('/(?Pf.*)(?Pb.*)/', 'Hello foobar', $matches); echo "f* => " . $matches['fstar']; // prints 'f* => foo' echo "b* => " . $matches['bstar']; // prints 'b* => bar' И второй: preg_match('/(?PH.*) (?Pf.*)(?Pb.*)/', 'Hello foobar', $matches); echo "f* => " . $matches['fstar']; // prints 'f* => foo' echo "b* => " . $matches['bstar']; // prints 'b* => bar' echo "h* => " . $matches['hi']; // prints 'h* => Hello' Есть много мнений о том, что не следует использовать регулярные выражения для обработки [X]HTML. Однако иногда возникает такая задача: К слову сказать полезно знать как происходит парсинг XML и HTML. Пример: вытащить вторую ссылку из страницы: $doc = DOMDocument::loadHTML(' <html> <body>Тест <a href="http://arts-up.ru">Первая ссылка</a> <a href="http://www.arts-up.ru">Вторая ссылка</a> </body> </html> '); echo $doc->getElementsByTagName('a') ->item(1) ->getAttribute('href'); // на выходе: http://www.arts-up.ru Перевел: Станислав Протасевич Раздел: Уроки PHP Дата: 7-02-2012, 06:35 | Добавил: WorldPad | Читали: 441 | Другие новости по теме:Комментарии:Оставить комментарий |
ОпросКак давно вы программируете на PHP? Поисковая статистика
Метки уроков.htaccess, class, denwer, error, file_get_contents, function, get_cache, Google, HTML, input, mysql, MySql PHP Apache, PHP, register_globals, return, SEO, str_replace(), template, Yandex, Отправка почты, Статья, браузер, будет, доступен, кеширование на php, комментарии, массив, поисковой, постраничная навигация, продвижение, работы, сайт, сервер, ссылки, статей, статьи, текст, текстов, функции, функция
Показать все теги |