Глюк регулярных выражений в PHP при работе с UTF-8
Нашел такую вещь: если указывать модификатор ‘u’ (PCRE_UTF8), который предписывает интерпретировать шаблон как строку в utf-8 (см. также http://ru2.php.net/manual/ru/reference.pcre.pattern.modifiers.php), для русских букв работает регистронезависимое сопоставление, но в то же время русские буквы не считаются буквами!
Особенно странное заключается в том, что без модификатора буква распознаётся (хотя регистронезависимое сопоставление, конечно же, не работает, что, впрочем, не странно):
Неожиданным оказалось, что, если сохранить скрипт, например, в кодировке cp-1251, то сопоставление букв разного регистра может проходить успешно:
Проверялось всё это на PHP 5.2.4 под Windows.
Немало удивил также результат проверки на PHP 5.1.6 под Linux: отсутсвие совпадения для всех шести описанных случаев, т.е. модификатор PCRE_UTF8 не работает вообще.
Что бы с этим сделать, как думаете?
rgbeast
А работает ли mb_ereg_replace? Функция конечно требует расширение mb.
06.12.2008, 11:06 Ответить
1234ru
echo mb_regex_encoding ( ‘utf-8’ ) ; // выведет 1 — установление кодировки прошло удачно echo mb_internal_encoding ( ‘utf-8’ ) ; // также выведет 1 (на всякий случай, чтобы внять все вопросы) echo mb_ereg_match ( ‘/г/ui’ , ‘Г’ ) ; // выводит пустую строку, => совпадения не было echo mb_ereg_match ( ‘/ \w /u’ , ‘Г’ ) ; // для этого примера и следующих также выводится пустая строка echo mb_ereg_match ( ‘/г/i’ , ‘Г’ ) ; echo mb_ereg_match ( ‘/ \w /’ , ‘Г’ ) ;
Такая же ситуация с mb_ereg(). Проверялось под Linux (PHP 5.1.6).
Кстати, я что-то не пойму, зачем было делать две разных функции: mb_ereg() и mb_ereg_match().
rgbeast
Синтаксис у функцмм другой, модификаторов нет: echo mb_ereg_match(‘г’, ‘Г’);
Опции — третий аргумент
07.12.2008, 01:20 Ответить
1234ru
Да, работает вот так: mb_ereg_match ( ‘г’ , ‘Г’ , ‘i’ ) ; (без модификатора ‘i’, кстати, не работает).
Работает и mb_eregi ( ‘г’ , ‘Г’ ) ; .
Но все равно мне все это не нравится. ereg_match() — отстой, массив вхождений не возвращает. eregi() — тоже — не принимает модификаторы.
Зачем вообще эти ereg()? Ведь надо ж было переделать под mb_ четыре функции: preg_match(), preg_match_all, preg_replace() и preg_replace_callback(). Пока этого нет, будет всё через одно место.
Представь себе это основные функции для работы с регулярками в ПХП.
А preg_& это Perl style, портированный в PHP по просьбам трудящихся.
По поводу того как использовать *ereg* функции, передавать модификаторы и получать вхождения достаточно развернуто сказано на php.net. А по поводу в чем сильные и слабые стороны обоих стандартов холи варов миллион было уже. В т.ч. и сравнительные тесты производительности найти не проблема.
Есть подозрения, что mb_preg* никогда не будет, именно потому что этот стиль подразумевает модификаторы, в т.ч. «u», А в ereg* модификаторов вообще небыло, вместо них плодят разные функции типа ereg i и mb_ereg.
И тут мы плавно подошли к главному, в ereg нет и не надо (!) модификаторов.
echo mb_ereg(‘Г’, ‘Г’); // так матчим echo mb_eregi(‘г’, ‘Г’); // так матчим регистронезависимо
в обоих случаях 3 параметр — массив вхождений.
1234ru
Что-то не нашел я в описании функции ereg() возможности передавать модификаторы.
Что будем делать, когда понадобятся ‘s’, ‘m’ и др.?
Нередко возникает задача, которую можно решить с помощью PCRE, а с помощью POSIX — нет. Думаю, использовать последние можно лишь не от хорошей жизни, когда разница в производительности даже в 2-3 раза важна, а в остальных случаях смысла я в этом не вижу.
Serg_pnz
1234ru , чем закончились изыскания? Сегодня пол-дня убил, ну не понимает preg_replace когда вводишь fefысывсы
upd: это тоже не прокатило
Serg_pnz
Не фонтан, но вроде работает для моей узкой задачи.
2admin: сделайте «шапку» для оформления кода php по примеру цитаты
16.03.2009, 15:57 Ответить
1234ru
1234ru
Изыскания закончились прочтением книги Дж. Фридла про регулярные выражения, в которой написано, что диалект PCRE интерпретирует символ \w точно как ASCII-[A-Za-z0-9] — не включая буквы остальных кодировок, хотя последовательности вида A-Я понимает.
P.S. Извините, что поздно ответил. Диссертация одолевает.
Serg_pnz
Дисс — нужная вещь, я вот в своё время не стал поступать(((
u должна быть u или U?
20.03.2009, 19:58 Ответить
1234ru
Странно.. Что, вот прямо приводимый мной пример не работает? Какая версия PHP?
Нет, дело не в плюсике. Плюсик на самом деле не нужен (это я нечаянно его поставил, а потом стереть забыл), хотя работать с ним и без него будет почти одинаково.
Да, кстати. У Вас точно файл в UTF-8? Проверьте на всякий случай.
Serg_pnz
В который раз выручили! Всё прекрасно работает и без изврата с перекодировкой.
21.03.2009, 15:01 Ответить
Serg_pnz
Еще одна заморочка для utf-8
Пользователь вводит данные на русском языке и проверка
уже не работает.
Пришлось извратиться так
1234ru
Если $regLoginTmp содержит нелатинские буквы, и данные в UTF-8, то нужно использовать не strlen, а mb_strlen (в стандартном пакете PHP её нет, нужно устанавливать доп. модуль)
Как бы то ни было, с рег. выражением Вы перемудрили: #(.)<1,1># — то же, что просто #.# 🙂 (кстати; вместо <1,1>можно писать просто <1>)
Serg_pnz
dskarataev
Так что же все-таки является самым правильным решением?
1.каждый раз при использовании регулярных выражений делать конвертацию через iconv() 2.переучиваться на синтаксис PHP (ereg) 3.100% решением является использование [a-zA-Zа-яА-Я0-9] и модификатора u
хотелось бы конечно третье 🙂
07.10.2010, 17:27 Ответить
1234ru
Так и есть. [a-zA-Z\dА-Яа-яЁё] — дедовский способ, который подходит практически для любой кодировки, если там соотв. символы следуют подряд. 100%-ность определяется тем, подряд ли следуют соотв. буквы в таблице символов.
Но есть более правильное решение: конкретно для UTF-8 PHP и Perl поддерживают так называемые свойства Юникода — аналог предопределенных классов (типа \w, \d и др.)
Классы эти имеют вид \p<что-то>. Например, \p — это буквы (есть также полная запись — \p), \p — прописные буквы, \p — кириллические символы и др. В общем, классов этих куча. Попозже как-нибудь ссылку найду (не забыть бы).
Поэтому современный цивилизованный способ — это выражение вида $pattern = ‘/ \p /u’ ; .
Источник
Почему не работает регулярка на php?
Регулярка на php должна находить слово «культурист» либо в начале строки, либо в конце либо, если оно в середине окружено круглыми скобками например: тест1 (культурист) тест2.
Подскажите, плиз, почему не работают обратные ссылки:
Не находит ничего (найдет только, если слово поставить в конце строки).
1 ответ 1
Небольшое упрощение
Для большей ясности сначала переведу Ваше регулярное выражение в одинарные кавычки:
Все дальнейшие регулярки тоже буду приводить в одинарных кавычках.
Устранение проблемы
Сперва дам простой способ устранения проблемы. Для ваших целей следует использовать такую регулярку:
– то есть вместо обратных ссылок \1 следует использовать рекурсивные подмаски (?1) . Разница в следующем:
обратные ссылки сопоставляются с конкретными текстовыми строками, которые были захвачены из текста подмаской
рекурсивные подмаски работают как «подпрограммы» – они подставляют указанную подмаску «как есть» на место вызова, независимо от того, какая строка была захвачена ей ранее (см.эквивалентную регулярку ниже)
Потестировать вживую предложенное решение можно здесь: https://regex101.com/r/3hOm5A/1 – заодно я добавил там тестовый пример со всеми кейсами.
Теперь главное: почему так происходит?
В своей регулярке Вы используете обратные ссылки совместно с альтернативным выбором. Как только первая альтернатива (культурист)$ отрабатывает, начинается вторая альтернатива ^\1 . При переходе от альтернативы к альтернативе все обратные ссылки как бы «обнуляются». То есть считается, что в пределах данной (второй) альтернативы ещё никакой текст для первой подмаски не был найден. Подмаска есть, но обратная ссылка уже не хранит текст, который был ей сопоставлен в предыдущей альтернативе. То же самое происходит при переходе к третьей альтернативе. Именно поэтому две последних альтернативы у Вас не работают. Они просто не имеют доступа к ранее найденному тексту.
В свою очередь моё решение использует не обратные ссылки, а рекурсивные подмаски. В данном случае первая подмаска подставляется в альтернативные ветки как есть. В результате моя регулярка становится эквивалентна следующей:
Источник
Не правильно работает функция preg_match()
Здравствуйте, задание: Написать функцию, которая выводит список файлов в заданной директории, которые содержат искомое слово. Директория и искомое слово задаются как параметры функции. Все написал правильно, загвоздка как я понимаю в функции preg_match(), которая должна искать соответствие регулярному выражению и возвращать 1 если соответствие есть, у меня возвращает везде ноль, хотя файл с таким текстом имеется, не могу понять в чем причина, может регулярное выражение составлено неправильно, хотя его проверял на сайте http://regexr.ru/ Ниже привожу полный код php:
P.S. Файл в соотвествующей директории создан и там присутствует искомое слово, проверял. Может дело в кодировке? В файле установил utf-8 без BOM.
1 ответ 1
Если я не ошибаюсь, у функции preg_match есть ограничение на количество принимаемых символов из источника 10000 символов.
Сама функция поиска у вас не совсем правильная: в том, что у вас сейчас есть вы ищите не слово, а просто набор каких-то букв в произвольном порядке, которые ограничиваются пробелами по сторонам. Я бы предложил сделать вот так:
Всё ещё ищете ответ? Посмотрите другие вопросы с метками php регулярные-выражения или задайте свой вопрос.
Похожие
Подписаться на ленту
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Источник
Preg match не работает php
Здесь могла бы быть ваша реклама
Покинул форум Сообщений всего: 4574 Дата рег-ции: Июль 2006 Откуда: Israel
Секрет Теперь, когда вы уже наверняка второпях отправили свой запрос, я расскажу вам простой секрет, который сэкономит вам уйму ожиданий, даже если первый ответ по теме последуем сразу же.
Само собой я знаю что ответят мне тут же, и если я посмотрю на сообщения на форуме, то пойму что в общем то я и не ошибаюсь. Но еще я точно замечу, что очень мало тем, в которых всего два ответа : вопрос автора и еще два сообщение вида Ответ + Спасибо
После этого приходится начинать уточнять этим неграмотным что мне надо. Они что, сами читать не умеют? А уточнять приходится. И иногда пока они переварят то что я им скажу проходит и не одна ночь..
Уверен что если бы я им сказал что у меня есть фиолетовый квадрат, и нужно превратить его в синий треугольник и я пытался взять кисточку, макнуть в банку и поводить ей по квадрату но почему то кисточка не принимала цвет краски в банке, то на мой вопрос — где взять правильные банки мне бы ответили гораздо быстрее предложив её открыть, а не тратить еще стольник на жестянку.
Поэтому с тех пор я строю свои вопросы по проверенной давным давно схеме: Что есть Что нужно получить Как я пытался Почему или что у меня не получилось.
На последок как оно происходит на форумах
Новичок: Подскажите пожалуста самый крепкий сорт дерева! Весь инет перерыл, поиском пользовался! Старожил: Объясни, зачем тебе понадобилось дерево? Сейчас оно в строительстве практически не используется. Новичок: Я небоскрёб собираюсь строить. Хочу узнать, из какого дерева делать перекрытия между этажами! Старожил: Какое дерево? Ты вообще соображаешь, что говоришь? Новичок: Чем мне нравиться этот форум — из двух ответов ниодного конкретного. Одни вопросы неподелу! Старожил: Не нравится — тебя здесь никто не держит. Но если ты не соображаешь, что из дерева небоскрёбы не строят, то лучше бы тебе сначала школу закончить. Новичок: Не знаите — лучше молчите! У меня дедушка в деревянном доме живёт! У НЕГО НИЧЕГО НЕ ЛОМАЕТСЯ. Но у него дом из сосны, а я понимаю, что для небоскрёба нужно дерево прочнее! Поэтому и спрашиваю. А от вас нормального ответа недождёшся. Прохожий: Самое крепкое дерево — дуб. Вот тебе технология вымачивания дуба в солёной воде, она придаёт дубу особую прочность: Новичок: Спасибо, братан! То что нужно.