Жадный members php. Регулярные выражения


Для заграничных гостей напечатали отдельное меню.

Идея разных прейскурантов далеко не нова. Например, на турецких курортах во многих магазинчиках три прайса: для местных, для немцев и для русских. Платежеспособность-то у всех разная. Вот и московский ресторан “Генацвале ” , забыв про грузинское гостеприимство, напечатал два варианта меню. Одно на русском языке с обычными ценами. Другое - на английском для иностранцев с ценами, задранными в два раза.

Просто чахохбили в заведении стоит 380 рублей. А за chahohbili надо уже заплатить 840 rub. Видимо, за блюдо "в переводе".

А что? Риск, считай, нулевой. Вряд ли залетный болельщик из Сенегала или Саудовской Аравии сможет прочитать русское меню и заподозрит подвох. Фанату дадут только меню на английском.

Прокололись ребята “Генацвале ” , когда случайно дали журналисту Станиславу Натанзону оба варианта. Внимательный гость и обнаружил подлог.

"Они (иностранные фанаты - Авт.) заплатят вам ваш дабл-прайс, ваши счета за подорожавший в пять раз клоповник. Они выложат бабло - и пойдут дальше веселиться. Пока вы сальными пальцами перелистываете барыши от "терпил иностранных". Потому что они понимают, что веселье - навсегда, а деньги - на миг" , - так обратился в соцсети Натанзон к столичной индустрии сервиса.

Можно подумать, произошла досадная ошибка. Официант накосячил. С кем не бывает. Но ведь уже на следующий день после Натанзона в ресторан пришел еще один дотошный журналист Алексей Доронин. Он прикинулся австралийцем и попросил меню. Ему принесли уже один вариант - английский с удвоенным ценником.

Я говорю вам, как есть: у нас ничего подобного не происходит, - ответил представитель “Генацвале ” на вопрос, почему ресторан начал баловаться двойными меню.

Хоть рестораторы и отказались признавать свою вину, но гневить народ дальше не стали. От высоких цен для иностранцев заведение отказалось. Скорая проверка Роспотребнадзора не нашла нарушений.

"Информация в СМИ о фактах различия цен в англоязычном и русском вариантах меню в ресторане Москвы при проверках не подтвердилась" , - заявили в ведомстве.

Сейчас инспекторы проверяют вообще все рестораны вокруг Лужников, чтобы история с двойными ценами не повторилась.

Два меню с разными ценами - это нарушение закона о правах потребителей, - рассказал адвокат Дмитрий Лесняк. - Штраф выписывается по статье 14.15 КоАП за "нарушение правил продажи отдельных видов товаров" . Ресторан может заплатить от 10 до 30 тысяч рублей.

КАК ЕЩЕ ОБМАНЫВАЮТ ТУРИСТОВ

Самые шальные деньги сейчас зашибают таксисты. В ход идут вообще все уловки.

Самое распространенное: заломить несусветную цену. Иностранцы не знают, сколько у нас стоит поездка, поэтому за дорогу из аэропорта готовы отдать 5 тысяч рублей. Хотя обычно за аналогичный рейс просят не больше 1400 рублей. Только пассажиров приходится брать не через агрегаторы, а самим искать у тротуара.

Еще вариант: можно сказать, что счетчик показывает стоимость поездки не в рублях, а в валюте. Давайте не 230 рублей, а 230 евро. Одно хорошо - на такой бессовестный обман решаются далеко не все. Да и обмануть получается не каждого туриста. Иностранцы тоже не дураки и умеют считать деньги.

Регулярные выражения, это очень мощный, но в то же время сложный для понимания, инструмент обработки строк. Опишу основные моменты. Регулярное выражение это шаблон строки. По этому шаблону можно искать вхождения, производить замену, проверять на соответствие шаблону.

Правила составление шаблона (pattern)

Границы шаблона должны обозначаться определенными символами, часто используют "/ ", но я предпочитаю использовать "# " потому, что от обилия прямых/обратных слешей может в глазах зарябить, а "решетки" обычно больше нигде не используются. Итак: "#ТутТелоРегулярногоВыражения# "

Внутри регулярного выражения используются скобки - это подвыражения, с которыми можно производить манипуляции, пример:

#^/catalog/(+)/(+)\.html.*#

Это выражение предназначено для получения параметров в строке URL . В начале строки идет спецсимвол "^ " - это означает начало строки. Далее идет "/catalog/ " - тут нет спецсимволов, это просто текст, который должен содержатся в строке. Затем встретили круглые скобки, т.е. дошли до первого подвыражения. В квадратных скобках обозначаются множество символов, которые могут быть в строке в этом месте. Знак "- " означает перечисление. Знак "\ " экранирует специальные символы. Таким образом, в первом подвыражении у нас могут идти БОЛЬШИЕ и маленькие буквы латинского алфавита, цифры от 0 до 9, знак подчеркивания, тире и точка. Тире и точка - это спецсимволы, но здесь они экранированы, поэтому здесь это просто символы. После квадратных скобок идет знак "+ " - это значит предыдущий символ (а у нас это множество символов заданное в квадратных скобках) может идти 1 или больше раз. Затем идет "/ " - это просто символ, и аналогичное второе подвыражение. Затем идет "\.html ", что означает текст ".html ". А затем спец символы ".* " точка означает любой символ, а звездочка любое количество предыдущего символа. Т.е. после ".html " может идти все что угодно.

Указание количества, квантификаторы

Выше мы уже рассмотрели такие символы, указывающие количество предыдущих символов, как + и * . Приведем все возможности указания количества:

Спецсимволы

Для некоторых групп символов есть специальные сокращения:

"Жадность"

Рассмотрим понятие жадности регулярного выражения. Например есть строка:

#()#

Читаем: подвыражение:

Вроди все верно, подвыражение подходит под:

Но оно также подходит под:

Его то мы и получим, т.к. регулярные выражения по умолчанию "жадные". Снять жадность можно с помощью модификатора "U ", вот так:

#()#U

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

После регулярного выражения могут идти модификаторы: "#ТутТелоРегулярногоВыражения#ТутМодификаторы " Виды модификаторов:

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

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

preg_replace

Поиск и замена:

Preg_replace (mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]]);

Каждое значение может быть строкой или массивом, в случае, если $subject массив - возвращается массив, иначе строка

preg_split

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

Preg_split (string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]]);

Возвращает массив, состоящий из подстрок заданной строки subject , которая разбита по границам, соответствующим шаблону pattern .


Одна из очень мощных и полезных возможностей языка PHP - поддержка регулярных выражений. Многих программистов, как начинающих, так и довольно опытных, пугает внешняя сложность и запутанность языка регулярных выражений. Но могу вас уверить - это того стоит. Применение регулярных выражений существенно облегчает работу по обработке текстов и слабо структурированных данных.


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


Я думаю, вы неоднократно сталкивались с ситуациями, когда у вас есть текст (например, в Microsoft Word) и вам надо найти в нём что-то важное. Если вы знаете, что именно ищете - всё просто: вызвали диалог поиска, ввели искомое слово, нажали кнопку и вуаля - текст найден.


Но что вы будете делать, если вы заранее знаете только тип искомой информации? Например, перед вами стоит задача найти все адреса электронной почты в документе на пару сотен листов. Некоторые будут просматривать документ вручную, некоторые - введут в поиске собаку (@) и будут искать её. Согласитесь - оба вариата это каторжный неблагодарный труд.

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

Регулярное выражение - это текстовая строка, составленная по определённым законам и правилам. Строка состоит из символов и групп символов, метасимволов, квантификаторов и модификаторов.

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

// читаемые символы a Е // нечитаемые символы и коды \x41 - то же что буква "A" \x09 - символ табуляции

Группа символов - это несколько символов, записанные последовательно:

Абвг ACZms

Сразу обращаю ваше внимание - "пробел" в регулярных выражения тоже рассматривается как значимый символ, поэтому при написании выражений будьте внимательны. Например, эти граппы символов являются РАЗНЫМИ выражениями:

АБВГДЕ АБВ ГДЕ

Следующий элемени языка - метасимволы. Приставка "мета" означает, что эти символы описывают некие другие символы или их группы. В таблице рассмотрены основные метасимволы языка регулярных выражений:

Метасимволы для задания специальных символов
() Скобки. Определяют вложенные выражения.
| Метасимвол выбора
^ Метасимвол начала строки
$ Метасимвол конца строки
\n Символ перевода строки (шестнадцатеричный код 0x0A)
\r Символ возврата каретки (шестнадцатеричный код 0x0D)
\t Символ табуляции (шестнадцатеричный код 0x09)
\xhh Вставка символа с шестнадцатиричным кодом 0xhh, например \x42 вставит латинскую букву "B"
Метасимволы для задания групп символов
. Точка. Любой символ.
\d Цифра (0-9)
\D Не цифра (любой символ кроме символов 0-9)
\s Пустой символ (обычно пробел и символ табуляции)
\S Непустой символ (все, кроме символов, определяемых метасимволом \s)
\w "Словарный" символ (символ, который используется в словах. Обычно все буквы, все цифры и знак подчеркивания ("_"))
\W Все, кроме символов, определяемых метасимволом \w

Метасимволы из второй половины таблицы очень легко запомнить. "d" - digit (цифра), "s" - symbol (символ), "w" - word (слово). Если буква большая - значит надо добавить "НЕ" в описанию группы.

Возьмём для примера текст "На красной майке цифры 1812, а на зелёной майке - 2009". Рассмотрим примеры простейших регулярных выражений:

\d\d\d\d - найдёт 1812 и 2009 \D - найдёт все буквы, пробелы и знаки препинания \s - найдёт все пробелы в тексте.

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

Означает любую цифру (то же, что \d) - означает чётную цифру - обозначает любой символ латниского алфавита (в любом регистре) или цифру.

Например, выражение \d\d\d в тестовой строке найдёт только 1812, но не 2009. Это выражение следует читат как "найти все последовательности из четырёх цифр, где последняя цифра равна 0,2,4,6 или 8".

Нам осталось упомянуть лишь квантификаторы и модификаторы.

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

Здесь Х - это количество раз, которое должен повториться предшествующий символ или группа. Например выражение

Вторая форма записи - диапазонная. Записывается как

{X, Y} // или {,Y} // или {X,}

где X - минимальное, а Y - максимальное количество повторений. Например:

читается как "от двух до четырёх последовательно записанных цифр". Если одна из границ не указана, то подразумевается отсутствие ограничения. Например:

\w{3,} - три и более букв. \d{,5} - цифр нет вообще, либо есть, но не более пяти.

Квантификаторы могут применяться как к одному символу, так и к группе:

[ А-Яа-я ]{1,3}

Эта конструкция выберет из текста все русские слова из одной, двух или трёх букв (например, "или", "не", "я", "иду" и т.п.)

Кроме фигурных скобок с уществует ещё три метасимвола-квантификатора: "*" (звёздочка), "+" (плюс) и "?" (вопрос). Их испльзуют в случаях, когда заранее неизвестно минимальное и максимальное количество необходимых повторений. Например, при поиске адресов электронной почты нельзя заранее сказать, сколько символов будет в имени пользователя (до "собаки"), а сколько - в имени домена (после "собаки").

Метасимвол "*" читается как "любое количество от нуля и более", т.е. конструкция

определяет любое количество последовательных букв, в том числе и их полное отсутствие.

Символ "+" отличается от звёздочки лишь тем, что требует наличия хотя-бы одного символа. Т.е. конструкция

соответствует любой цифровой последовательности, где цифр одна или более.

Символ "?" соответствует отсутствию или наличию единственного символа. Т.е. конструкция

соответствует любой цифровой последовательности, где цифр одна или две.

Здесь стоит упомянуть о такой особенности антификаторов "*" и "+" как жадность . Суть в том, что по-умолчанию эти символы соответствуют максимально длинной последовательности символов. Например, для строки "мама мыла раму" выражение:

выберет "мама мыла ра", что несколько неожиданно, ведь мы предполагали получить "ма". Для изменения такого поведения используется метасимвол "?" (знак вопроса), записанный сразу после квантификатора. Он органичивает "аппетит" квантификаторов, заставляя их возвращать первое совпадение, а не самое длинное. Теперь изменим предыдущий пример:

и получим требуемое совпадение "ма".

Последний элемент языка - модификаторы . Модификатор - это спецсимвол, определяющий "системные" параметры анализа регулярных выражений. Таких символов всего четыре, они могут применяться как по отдельности, так и одновременно:

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

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

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

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

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

Функция проверяет, совпадает ли содержимое subject с шаблоном pattern. Возвращает 1, если совпадения найдены, иначе возвращает 0. Если указать необязательный параметр-массив matches, то при выполнении функции в него будут занесен единственный элемент - первое найденное совпадение.

"; print_r($found); ?>

int preg_match_all (string pattern, string subject, array matches [, int order])
Функция идентична предыдущей, с единственным отличием - она производит поиск по всему тексту и возвращает в массиве matches ВСЕ найденные совпадения.
mixed preg_replace (mixed pattern, mixed replacement, mixed subject [, int limit])
Как и обе предшествующие функции, preg_replace производит поиск фрагмента текста, соответствующего шаблону. Все найденные фрагменты функция заменяет на указанный в параметрах текст. До очистки:\n$text\n\n"; $text = preg_replace("/(\n \s{2,})/"," ",$text); echo "После очистки:\n$text"; // выведет текст, очищенный от спецсимволов // и лишних пробелов?>
mixed preg_replace_callback (mixed pattern, mixed callback, mixed subject [, int limit])
Функция является расширенной версией предыдущей. Главное отличие - этой функции в параметрах передаётся имя функции, которая будет анализировать текст и формировать замещающий текст.
array preg_split (string pattern, string subject [, int limit [, int flags]])
Эта функция аналогична функциям explode() и split(). Её особенность в том, что в качестве разделителя выступает не фиксированная строка, а регулярное выражение. Функция разбивает исходные данные на элементы и помещает их в выходной массив.
array preg_grep (string pattern, array input)
Функция предназначена для регулярного поиска в массивах. Для поиска задаётся шаблон и массив входных данных, а возвращается массив, состоящий только из элементов, соответствющих шаблону.

Рассмотренный список функций далеко не полон, но вполне достаточен для успешного начала работы с регулярными выражениями. Если вы заинтересовались этой темой - обязательно почитайте дополнительную литературу (например, книгу Фридла "Регулярные выражения"). Кроме того, в целях обучения рекомендую поставить одну из специальных программ для тестирования регулярных выражений (например, "PCRE" или "RegEx Builder").

Я когда-то писал о . Так вот, мы с Вами там рассмотрели только "жадных " представителей. Однако, не всегда их "жадность " нам помогает, очень часто она и вредит. Чуть ниже я покажу пример, где чётко видно то, что они иногда делают, а также покажу как уменьшить их пыл и сделать квантификаторы повторений "ленивыми" .

Давайте разберём простой и уже ставший классическим пример:

$str = "Небольшая строка c жирным выделением.";
.*<\/b>
echo $result_str;
?>

Возможно, Вы ожидаете что-то наподобие этого: "Небольшая здесь_жирное_выделение с здесь_жирное_выделение выделением ". То есть просто замена содержимого внутри тега <b > на заданную нами строку вместе с самим тегом. Однако, это не совсем так, поскольку здесь вступает в игру "жадность квантификаторов ". И в результате замена была не внутри каждого тега <b >, а от самого первого открывающего тега до самого последнего закрывающего. В этом и состоит жадность.

Вот как надо писать данный код, чтобы замена происходила так, как мы хотим:

$str = "Небольшая строка c жирным выделением.";
$result_str = preg_replace("/.*?<\/b>/i", "здесь_жирное_выделение", $str);
echo $result_str;
?>

Всё, что мы изменили это регулярное выражение, поставив после квантификатора повторений ".* " знак вопроса, который как раз и делает квантификатор "ленивым" . Теперь результатом будет: "Небольшая здесь_жирное_выделение c здесь_жирное_выделение выделением. ", чего мы и пытались добиться.

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