Как стать автором
Обновить

Примеры использования регулярных выражений на php

При написании различных, веб-приложений, приходилось использовать различные регулярные выражения. И так как я особо их до конца не понимаю, то использовал частенько чужие примеры, только потом «затачивал» их под себя.
Вот решил с вами поделиться с популярными задачами и их решениями:

Получить расширение файла



preg_replace("/.*?\./", '', 'photo.jpg');

Взять то, что находится между тегами и



if (preg_match('|<title.*?>(.*)|sei', $str, $arr)) $title = $arr[1];
else $title='';

Обратите внимание: берется не нулевой элемент массива, а первый!
Если title будет встречаться несколько раз, то будет вырезано от первого и до последнего!

Найти текст, заключенный в какой-то тег и заменить его на другой тег


Например: … заменить аналогично на <МОЙ_ТЕГ>… </МОЙ_ТЕГ> в HTML-файле:

preg_replace("!(.*?)!si","<МОЙ_ТЕГ>\\1</МОЙ_ТЕГ>",$string);


Проверяем, является ли переменная числом



if (!preg_match("|^[\d]+$|", $var)) ...

Запретим пользователю использовать в своем имени любые символы, кроме букв русского и латинского алфавита, знака "_" (подчерк), пробела и цифр:



if (preg_match("/[^(\w)|(\x7F-\xFF)|(\s)]/",$username)) {
echo "invalid username";
exit;
}


Проверка адреса e-mail


Для поля ввода адреса e-mail добавим в список разрешенных символов знаки "@" и "." и "-",
иначе пользователь не сможет корректно ввести адрес. Зато уберем русские буквы и пробел:
if (preg_match("/[^(\w)|(\@)|(\.)|(\-)]/",$usermail)) {
echo "invalid mail";
exit;
}


Проверка на число


if(preg_match('/^\d+$/', $var)) echo $var;


Проверка имени файла



if (ereg("(^[a-zA-Z0-9]+([a-zA-Z\_0-9\.-]*))$" , $filename)==NULL) {
echo "invalid filename";
exit;
}


Проверка расширения файла


Архивы (zip, rar, ...)



/\.(?:z(?:ip|[0-9]{2})|r(?:ar|[0-9]{2})|jar|bz2|gz|tar|rpm)$/i

Аудио (mp3, wav, ...)



/\.(?:mp3|wav|og(?:g|a)|flac|midi?|rm|aac|wma|mka|ape)$/i

Программы (exe, xpi, ...)



/\.(?:exe|msi|dmg|bin|xpi|iso)$/i

Изображения (jpg, png, ...)



/\.(?:jp(?:e?g|e|2)|gif|png|tiff?|bmp|ico)$/i

Видео (mpeg, avi, ...)



/\.(?:mpeg|ra?m|avi|mp(?:g|e|4)|mov|divx|asf|qt|wmv|m\dv|rv|vob|asx|ogm)$/i


Выбрать все изображения со страницы


Как-то мне нужно было получить все изображения, которые использовались на
сайте. Что для этого надо сделать? Правильно, надо в браузере нажать на
«Сохранить как», указать куда сохранить страницу. Появится файл с исходным кодом
страницы и папка с изображениями. Но вы никогда не сохраните в эту папку
изображения, которые прописаны в стилях объектов по крайней мере в эксплорере:



style="background-image:url(/editor/em/Unlink.gif);"

Для проведения вышеописанной операции надо:
1. попросить хозяина хоста использовать контент, размещенный на его сайте.
2. найти в тексте все строки, подобные приведенной выше, и выделить в них относительный путь к файлу
3. сформировать файл в котором будут выводиться изображения при помощи:

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



Начнем с простого. Символы латинского алфавита, цифры, точка и слеш описываются символьным классом: [a-z.\/]
их может быть сколько угодно, на самом деле больше 3 (имя файла, минимум один
символ, точка, расширение, минимум один символ), но в данном случае, зная
контекст, это некритично, поэтому указываем квантификатор * [a-z.\/]* Слева
должны идти 'url(' и мы это описываем при помощи позитивной ретроспективной
проверки: (?<=url() Но обратите внимание на то, что скобка в регулярных
выражениях является спецсимволом группировки, поэтому чтобы она стала символом,
надо перед ней поставить другой спецсимвол — слеш. (?<=url\() Справа от
относительного пути должна стоять закрывающаяся круглая скобка. Это условие
описывается при помощи позитивной опережающей проверки: (?=\)) Как видите, перед
одной из скобок стоит слеш, что означает, что она интепретируется не как
спецсимвол, а как литерал. Ниже приведен полный код на PHP, который выполняет
все действия, кроме вопроса о разрешении использовать контент:



preg_match_all("/(?<=url\()[a-z.\/]*(?=\))/i", $content, $matches);
foreach($matches[0] as $item)
{ echo ""; }


Парсер всех внешних и внутренних ссылок со страницы


В массиве $vnut только ссылки внутренние, в массиве $vnech только внешние ссылки.
$html=file_get_contents ('http://www.popsu.net');
$url='popsu.net';
$vnut=array();
$vnech=array();
preg_match_all('~<a [^<>]*href=[\'"]([^\'"]+)[\'"][^<>]*>(((?!~si',$html, $matches);
foreach ($matches[1] as $val) {
if (!preg_match("~^[^=]+://~", $val) || preg_match("~^[^://]+://(www\.)?".$url."~i", $val)) { $vnut[]=$val; }
else $vnech[]=$val;
}
$vnut=array_unique ($vnut);
$vnech=array_unique ($vnech);
print_r ($vnut);
print_r ($vnech);


Является ли строка числом, длиной до 77 цифр:



if (ereg("^[0-9]{1,77}$",$string)) echo "ДА";


Состоит ли строка только из букв, цифр и "_", длиной от 8 до 20 символов:



if (ereg("^[a-zа-я0-9_]{8,20}$",$string)) echo "yes"; else echo "no";


Проверка строки на допустимость


Есть ли в строке любые символы, кроме допустимых. Допустимыми считаются
буквы, цифры и "_". Длину тут проверять нельзя,
разве что просто дополнительным условием strlen($string). Не путайте с предыдущим
примером — хоть результат и одинаковый, но метод другой, «от противного»
:)

if ( ! ereg("[^a-zа-я0-9_]",$string))
echo "нет посторонних букв (OK)";
else
echo "есть посторонние буквы (FALSE)";

Для регистро независимого сравнения используйте eregi().

Проверка повторяющихся символов


Есть ли в строке идущие подряд символы, не менее 3-х символов
подряд (типа «абвгДДДеё», но не «ааббаабб»):

if (preg_match("/(.)\\1\\1/",$string)) echo "yes"; else echo "no";


Заменить везде в тексте СТРОКУ1 на СТРОКУ2


(задача решается без регулярных выражений):

$string=str_replace("СТРОКА1","СТРОКА2",$string);


Заменить кривые коды перехода строки на нормальные:


для этого нужно только удалить "\r". Переходы бывают нормальными (но разными!):
"\n" или "\r\n". Еще бывают глюки, типа "\r\r\n".
$string=str_replace("\r","",$string);


Заменить все повторяющиеся пробелы на один


Не пытайтесь здесь применить str_replace, это хорошая функция, но не
для данного примера.

$string=preg_replace("/ХХ+/","Х",$string); // вместо Х поставьте пробел


Удаление многократно повторяющихся знаков препинания


Удаление знаков препинания, которые повторяются больше 3 раз, т.е.!!! -> !!!, ????? -> ??? и т.д.
Заменяются следующие символы:.!? ( )
$text = preg_replace('#(\.|\?|!|\(|\)){3,}#', '\1\1\1', $text);


Сложная замена


В тексте есть некоторые слова, допустим «СЛОВО» и «ЛЯЛЯЛЯ» (и т.д.),
которые нужно одинаковым образом заменить на тоже самое, но
с добавками. Возможно, слова отсутствуют или встречаются много раз
в любом регистре.
Т.е. если было «слово» или «СлОвО» (или еще как),
нужно заменить это на "слово" или "СлОвО" (смотря, как было).
Другими словами нужно найти перечень слов в любом регистре и вставить
по краям найленных слов фиксированные строки (на "" и "").

$string=preg_replace("/(слово1|слово2|ляляля|слово99)/si","\\1",$string);


Проверка URL на корректность


Поддерживает все, что только может быть в УРЛ…
Помните о том, что вы должны не только проверять, но и принимать новое значение
от функции, т.к. та дописывает «http://» в случае его отсутствия.
// функция для удаления опасных сиволов
function pregtrim($str) {
return preg_replace("/[^\x20-\xFF]/","",@strval($str));
}

//
// проверяет URL и возвращает:
// * +1, если URL пуст
// if (checkurl($url)==1) echo "пусто"
// * -1, если URL не пуст, но с ошибками
// if (checkurl($url)==-1) echo "ошибка"
// * строку (новый URL), если URL найден и отпарсен
// if (checkurl($url)==0) echo "все ок"
// либо if (strlen(checkurl($url))>1) echo "все ок"
//
// Если протокола не было в URL, он будет добавлен ("http://")
//
function checkurl($url) {
// режем левые символы и крайние пробелы
$url=trim(pregtrim($url));
// если пусто - выход
if (strlen($url)==0) return 1;
//проверяем УРЛ на правильность
if (!preg_match("~^(?:(?:https?|ftp|telnet)://(?:[a-z0-9_-]{1,32}".
"(?::[a-z0-9_-]{1,32})?@)?)?(?:(?:[a-z0-9-]{1,128}\.)+(?:com|net|".
"org|mil|edu|arpa|gov|biz|info|aero|inc|name|[a-z]{2})|(?!0)(?:(?".
"!0[^.]|255)[0-9]{1,3}\.){3}(?!0|255)[0-9]{1,3})(?:/[a-z0-9.,_@%&".
"?+=\~/-]*)?(?:#[^ '\"&<>]*)?$~i",$url,$ok))
return -1; // если не правильно - выход
// если нет протокала - добавить
if (!strstr($url,"://")) $url="http://".$url;
// заменить протокол на нижний регистр: hTtP -> http
$url=preg_replace("~^[a-z]+~ie","strtolower('\\0')",$url);
return $url;
}

Таким образом для проверки нужно использовать нечто такое:

$url=checkurl($url); // перезаписали УРЛ в самого себя
if ($url) exit("Ошибочный URL");


// Returns true if «abc» is found anywhere in $string.

ereg("abc", $string);


// Returns true if «abc» is found at the beginning of $string.

ereg("^abc", $string);


// Returns true if «abc» is found at the end of $string.

ereg("abc$", $string);


Возвращает true если browser = Netscape 2, 3 or MSIE 3.



eregi("(ozilla.[23]|MSIE.3)", $_SERVER["HTTP_USER_AGENT"]);


// Places three space separated words into $regs[1], $regs[2] and $regs[3].

ereg("([[:alnum:]]+) ([[:alnum:]]+) ([[:alnum:]]+)", $string, $regs);


Добавить
в начало всех строк



$string = ereg_replace("^", "
", $string);


Добавить
в конец всех строк



$string = ereg_replace("$", "
", $string);

// Get rid of any newline characters in $string.

$string = ereg_replace("\n", "", $string);


Удалить все аттрибуты у всех тегов, кроме a, p, img



preg_replace("/<([^ap(img)].*?)\s.*?>/is", "<\\1>", $string);


Выбрать локальные URL


Как можно выбрать не просто все урлы в HTML странице а те которые не начинаются на http://, другими словами локальные.

preg_match_all("#\s(?:href|src|url)=(?:[\"\'])?(.*?)(?:[\"\'])?(?:[\s\>])#i", $buffer, $matches);


Выбрать все параметры:



$string = '

Array
(
[0] => Array
(
[0] => border='0'
[1] => cellpadding = "0"
[2] => cellspacing=0
[3] => style= "border-collapse: collapse"
)

[1] => Array
(
[0] => border
[1] => cellpadding
[2] => cellspacing
[3] => style
)

[2] => Array
(
[0] => '0'
[1] => "0"
[2] => 0
[3] => "border-collapse: collapse"
)

[3] => Array
(
[0] => 0
[1] => 0
[2] =>
[3] => border-collapse: collapse
)

[4] => Array
(
[0] =>
[1] =>
[2] => 0
[3] =>
)

)

Конвертор HTML в текст


// $document на выходе должен содержать HTML-документ.
// Необходимо удалить все HTML-теги, секции javascript,
// пробельные символы. Также необходимо заменить некоторые
// HTML-сущности на их эквивалент.

$search = array ("'<script[^>]*?>.*?'si", // Вырезает javaScript
"'<[\/\!]*?[^<>]*?>'si", // Вырезает HTML-теги
"'([\r\n])[\s]+'", // Вырезает пробельные символы
"'&(quot|#34);'i", // Заменяет HTML-сущности
"'&(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"); // интерпретировать как php-код

$replace = array ("",
"",
"\\1",
"\"",
"&",
"<",
">",
" ",
chr(161),
chr(162),
chr(163),
chr(169),
"chr(\\1)");

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



Найти и заменить все "http://" на ссылки



Вариант 1:


$text = preg_replace('#(?<!\])\bhttp://[^\s\[<]+#i',
"Посмотреть на сайте",
nl2br(stripslashes($text)));

<br>

Вариант 2, с выделением домена:


// Cuts off long URLs at $url_length, and appends "..."
function reduceurl($url, $url_length) {
$reduced_url = substr($url, 0, $url_length);
if (strlen($url) > $url_length) $reduced_url .= '...';
return $reduced_url;
}

$linktext = preg_replace("#\[(([a-zA-Z]+://)([a-zA-Z0-9?&%.;:/=+_-]*))\]#e", "'' . reduceurl(\"$3\", 30) . ''", $linktext);


Еще один вариант, учитывающий "WWW."
// match protocol://address/path/file.extension?some=variable&another=asf%
$text = preg_replace("/\s(([a-zA-Z]+:\/\/)([a-z][a-z0-9_\..-]*[a-z]{2,6})([a-zA-Z0-9\/*-?&%]*))\s/i", " $3 ", $text);

// match www.something.domain/path/file.extension?some=variable&another=asf%
$text = preg_replace("/\s(www\.([a-z][a-z0-9_\..-]*[a-z]{2,6})([a-zA-Z0-9\/*-?&%]*))\s/i", " $2 ", $text);


Разбор адесов E-mail.


$text = "Адреса: user-first@mail.ru, second.user@mail.ru.";
$html = preg_replace(
'{
[\w-.]+ # имя ящика
@
[\w-]+(\.[\w-]+)* # имя хоста
}xs',
'$0
',
$text
);
echo $html;

То же самое, но немножко по-другому:

$html = preg_replace( '/(\S+)@([a-z0-9.-]+)/is', '$0', $text);


Проверить, что в строке есть число (одна или более цифра)



preg_match('/(\d+)/s', "article_123.html", $pockets);
// Совпадение (подвыражение в скобках) окажется в $pockets[1].
echo $pockets[1]; // выводит 123


Найти в тексте адрес E-mail



// \S означает "не пробел", а [a-z0-9.]+ -
// "любое число букв, цифр или точек". Модификатор 'i' после '/'
// заставляет PHP не учитывать регистр букв при поиске совпадений.
// Модификатор 's', стоящий рядом с 'i', говорит, что мы работаем
// в "однострочном режиме" (см. ниже в этой главе).
preg_match('/(\S+)@([a-z0-9.]+)/is', "Привет от somebody@mail.ru!", $p);
// Имя хоста будет в $p[2], а имя ящика (до @) - в $p[1].
echo "В тексте найдено: ящик - $p[1], хост - $p[2]";


Превращение E-mail в HTML-ссылку.


$text = "Привет от somebody@mail.ru, а также от other@mail.ru!";
$html = preg_replace(
'/(\S+)@([a-z0-9.]+)/is', // найти все E-mail
'$0
', // заменить их по шаблону
$text // искать в $text
);
echo $html;


Простейший разбор даты.


$str = " 15-16/2000 "; // к примеру
$re = '{
^\s*( # начало строки
(\d+) # день
\s* [[:punct:]] \s* # разделитель
(\d+) # месяц
\s* [[:punct:]] \s* # разделитель
(\d+) # год
)\s*$ # конец строки
}xs';
// Разбиваем строку на куски при помощи preg_match().
preg_match($re, $str, $pockets) or die("Not a date: $str");
// Теперь разбираемся с карманами.
echo "Дата без пробелов: '$pockets[1]' <br>";
echo "День: $pockets[2] <br>";
echo "Месяц: $pockets[3] <br>";
echo "Год: $pockets[4] <br>";


Замена по шаблону



$text = htmlspecialchars(file_get_contents(__FILE__));
$html = preg_replace('/(\$[a-z]\w*)/is', '$1', $text);
echo "$html
";


Обратные ссылки


$str = "Hello, this word is bold!";
$re = '|<(\w+) [^>]* > (.*?) </\1>|xs';
preg_match($re, $str, $pockets) or die("Нет тэгов.");
echo htmlspecialchars("'$pockets[2]' обрамлено тэгом '$pockets[1]'");


"Жадные" квантификаторы



$str = "Hello, this word is bold!";
$re = '|<(\w+) [^>]* > (.*) </\1>|xs';
preg_match($re, $str, $pockets) or die("Нет тэгов.");
echo htmlspecialchars("'$pockets[2]' обрамлено тэгом '$pockets[1]'");


Сравнение "жадных" и "ленивых" квантификаторов



$str = '[b]жирный текст [b]а тут - еще жирнее[/b] вернулись[/b]';
$to = '$1';
$re1 = '|\[b\] (.*) \[/b\]|ixs';
$re2 = '|\[b\] (.*?) \[/b\]|ixs';
$result = preg_replace($re1, $to, $str);
echo "Жадная версия: ".htmlspecialchars($result)."<br>";
$result = preg_replace($re2, $to, $str);
echo "Ленивая версия: ".htmlspecialchars($result)."<br>";


Многострочность.



$str = file_get_contents(__FILE__);
$str = preg_replace('/^/m', "\t", $str);
echo "".htmlspecialchars($str)."
";


Использование PREG_OFFSET_CAPTURE



$st = 'жирный текст';
$re = '|<(\w+).*?>(.*?)</\1>|s';
preg_match($re, $st, $p, PREG_OFFSET_CAPTURE);
echo ""; print_r($p); echo "
";


Применение preg_grep()



foreach (preg_grep('/^ex\d/s', glob("*")) as $fn)
echo "Файл примера: $fn<br>";


Различные флаги preg_match_all()


Header("Content-type: text/plain");
$flags = array(
"PREG_PATTERN_ORDER",
"PREG_SET_ORDER",
"PREG_SET_ORDER|PREG_OFFSET_CAPTURE",
);
$re = '|<(\w+).*?>(.*?)</\1>|s';
$text = "текст и еще другой текст";
echo "Строка: $text\n";
echo "Выражение: $re\n\n";
foreach ($flags as $name) {
preg_match_all($re, $text, $pockets, eval("return $name;"));
echo "Флаг $name:\n";
print_r($pockets);
echo "\n";
}


preg_replace_callback()


// Пользовательская функция. Будет вызываться для каждого
// совпадения с регулярным выражением.
function toUpper($pockets) {
return $pockets[1].strtoupper($pockets[2]).$pockets[3];
}
$str = 'Three captains, one ship.';
$str = preg_replace_callback('{(</?)(\w+)(.*?>)}s', "toUpper", $str);
echo htmlspecialchars($str);



Получение строки GET-запроса.


Для начала поставим самую простую задачу - получить часть URL, содержащую GET-параметры.


function ggp($url) { // get GET-parameters string
preg_match('/^(.+?)(\?.*?)?(#.*)?$/', $url, $matches);
$gp = (isset($matches[2])) ? $matches[2] : '';
return $gp;
}

Не стоит забывать, что адрес может вовсе не содержать никакого GET-запроса, и массив вхождений может не иметь второго элемента 3.

Исключение GET-запроса из URL.


Иногда нужно получить URL без GET-параметров (например, при перенаправлении запросов
с помощью mod_rewrite зачастую требуется проводить анализ URL,
чтобы сформировать ответ клиенту;
нередко для анализа нужна только статическая часть URL,
а часть, где передается GET-запрос, не нужна и даже мешает).
// удаление GET-параметров из URL
$str = preg_replace('/^(.+?)(\?.*?)?(#.*)?$/', '$1$3', $url);


заменить все символы кроме чисел и запятой на ''


$value = preg_replace('/[^\d,]+/', '', $value); // заменить все символы кроме чисел и запятой на ''


Есть ли в строке параметров сессия (PHPSESSID):


print $_SERVER['REQUEST_URI'].'<br>';
if (preg_match("/=([a-f0-9]{32})&/i", $_SERVER['REQUEST_URI'].'&')){
print 'Да';
// удалить сессию из строки параметров
//print str_replace('&&','&',str_replace('?&','?',preg_replace("/&*sid=([a-f0-9]{32})&*/i", '&', $_SERVER['REQUEST_URI'])));
}
else print 'Нет';


Удалить из строки параметр page и добавить другой page.


Этот пример позволяет заменить один параметр на другой не испортив все остальные параметры строки.
Если Вы найдете более оптимальное решение, присылайте.
$href1=str_replace('&&','&',str_replace('?&','?',preg_replace("/&*page=([0-9]{1,3})&*/i", '&', $_SERVER['REQUEST_URI'])));
$href1=str_replace('?&','?',$href1.(strpos($href1, '?')===false?'?':'&').'page=');


Ссылка на ресурс

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.