особенности UTF-8 при работе с регулярными выражениями

Использование системы в различных ситуациях, вопросы программирования сценариев.

Модератор: immortal

Ответить
Аватара пользователя
Vovix
Сообщения: 1155
Зарегистрирован: Пн янв 27, 2014 1:43 am
Откуда: г.Ижевск
Благодарил (а): 60 раз
Поблагодарили: 532 раза
Контактная информация:

особенности UTF-8 при работе с регулярными выражениями

Сообщение Vovix » Вт дек 08, 2015 11:10 pm

Заметил тут одну интересную вещь, связанную с тем, что в системе используется кодировка UTF-8:
В кодировке UTF-8 унаследованы однобайтные (точнее, 7-битные) коды символов ASCII-7 (коды от 0 до 127), т.е. одним байтом кодируются латинские буквы, цифры и специальные символы. Русские буквы (кириллица) представляются 16-битными (двухбайтными) кодами
Так вот, еще при работе над своим виджетом (приложением) To Do я заметил, что для обработки строк русских букв обычные строковые функции PHP не подходят, например если надо было узнать длину слова, скажем: ВАСЯ, то выяснялось, что его длина при применении функции strlen будет равна 8, а не 4 и всё-бы ни чего, просто дели длину на 2 и всё будет окей, но например длина фразы в которой есть и русские и англ.буквы или спец.символы (хотя-бы даже пробел) уже таким способом правильно определяться не будет!

А вот для этих целей, как раз, есть: Строковые функции Multibyte - в принципе тут доступно описано, суть в изменении наименования функции - чаще всего добавление mb_ в начале. Ну и нужно не забыть указать для PHP с чем он будет работать далее в коде - mb_internal_encoding("UTF-8");
Применив это всё там (в To Do) я и почти забыл про это и тут.....

Некоторое время я не пользовался Android приложением MajorDroid, а тут включив его и начав голосовое управление, я обнаружил, что Google стал по другому возвращать некоторые распознанные фразы, а именно произнесенное слово "включи" выдается именно как Включи (с большой буквы), а слово "включить" - как включить (с маленькой).
И всё бы ничего, можно было, конечно, отлавливать это в шаблонах в строках поиска (либо через "или" либо еще вывернуться), но у меня например шаблон Включи или выключи это один шаблон, а не два и что именно сделать определяется внутри. Обращаю внимание, что сам начальный контекст системой обрабатывается правильно - т.е. у меня шаблон: (^включи|^выключи) отрабатывает правильно, не зависимо от того заглавная первая буква или прописная, но внутри зависимые шаблоны должны были разобраться, что от них всё-таки хотят: включить или выключить.
Дак вот был, и ранее как мне казалось, успешно работал например этот код:

Код: Выделить всё

if (preg_match('/включи/is',$original)) {
  say('Включаю передачу звука в сеть WiFi',1);
  runScript('audio_wifi_start');
} elseif (preg_match('/выключи/is',$original)) {
  say('Выключаю передачу звука в сеть WiFi',1);
  runScript('audio_wifi_stop');
} else {
  say('Непонятно что: '.$original,1);
} 
в котором, по сути, в функции preg_match используется модификатор is часть "i" из которого как раз задает регистронезависимый поиск, но он в данном случае НЕ РАБОТАЕТ! И кажется мне, что как раз из-за UTF-8 ?!

Что я предпринимал, чтобы решить эту проблему:
1) добавил mb_internal_encoding("UTF-8");
2) функцию preg_match заменил на mb_ereg_match
но НЕ РАБОТАЕТ так всё-равно!

Пока конечно поступил не красиво, а именно так:

Код: Выделить всё

if (preg_match('/включи/is',$original)||preg_match('/Включи/is',$original)) {....... 
но ведь должен-же быть способ правильно заставить работать PHP с русским языком в UTF-8...
может надо, что-то в php.ini подправить (добавить)?
Мой -CONNECT-
Windows 7(PHP 7.2) + Raspberry Pi(освещение на 1-Wire) + MP751(управление) + ESP8266(сенсоры) + LAN(сенсоры)
-=: Если вам помогло моё сообщение, нажмите кнопку "Поблагодарить за сообщение автора: Vovix" (кнопка Спасибо) справа! :=-
Аватара пользователя
AHgpeu
Сообщения: 117
Зарегистрирован: Чт мар 12, 2015 11:46 am
Благодарил (а): 26 раз
Поблагодарили: 16 раз

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение AHgpeu » Вт дек 08, 2015 11:31 pm

в PHP 5.4 починили косяк с \W, с русскими теперь нормально работает (при указании модификатора u).
соответственно и pcre обновить
найдено за пару минут гугления.
Аватара пользователя
Vovix
Сообщения: 1155
Зарегистрирован: Пн янв 27, 2014 1:43 am
Откуда: г.Ижевск
Благодарил (а): 60 раз
Поблагодарили: 532 раза
Контактная информация:

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение Vovix » Ср дек 09, 2015 12:09 am

AHgpeu писал(а):в PHP 5.4 починили косяк с \W, с русскими теперь нормально работает (при указании модификатора u).
соответственно и pcre обновить
найдено за пару минут гугления.
несколько месяцев назад, я помню, пытался обновить PHP внутри проекта - итогом была не рабочая система! может у меня руки не из того места растут?
Я понимаю, что этот косяк когда нибудь должны были исправить - а c PHP 6 , наверно, вообще наступит полная "нирвана"! Но сейчас пока... работаю на имеющемся. И я, так думаю, не один такой!
Мой -CONNECT-
Windows 7(PHP 7.2) + Raspberry Pi(освещение на 1-Wire) + MP751(управление) + ESP8266(сенсоры) + LAN(сенсоры)
-=: Если вам помогло моё сообщение, нажмите кнопку "Поблагодарить за сообщение автора: Vovix" (кнопка Спасибо) справа! :=-
Аватара пользователя
Vovix
Сообщения: 1155
Зарегистрирован: Пн янв 27, 2014 1:43 am
Откуда: г.Ижевск
Благодарил (а): 60 раз
Поблагодарили: 532 раза
Контактная информация:

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение Vovix » Ср дек 09, 2015 12:13 am

сейчас еще так переписал код:

Код: Выделить всё

// установим внутреннюю кодировку символов
mb_internal_encoding("UTF-8");

$on1 = mb_stripos($original,'включи');
$off1 = mb_stripos($original,'выключи');


if ($on1 === false) {
    } else {
        say('Включаю передачу звука в сеть WiFi',1);
          runScript('audio_wifi_start');
    }

if ($off1 === false) {
    } else {
        say('Выключаю передачу звука в сеть WiFi',1);
          runScript('audio_wifi_stop');
    }

if (($on1 === false)&($off1 === false)) {
    say('Непонятно что: '.$original,1);
} 
вроде работает так правильно!
Мой -CONNECT-
Windows 7(PHP 7.2) + Raspberry Pi(освещение на 1-Wire) + MP751(управление) + ESP8266(сенсоры) + LAN(сенсоры)
-=: Если вам помогло моё сообщение, нажмите кнопку "Поблагодарить за сообщение автора: Vovix" (кнопка Спасибо) справа! :=-
Аватара пользователя
Vovix
Сообщения: 1155
Зарегистрирован: Пн янв 27, 2014 1:43 am
Откуда: г.Ижевск
Благодарил (а): 60 раз
Поблагодарили: 532 раза
Контактная информация:

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение Vovix » Ср дек 09, 2015 12:16 am

просто я вижу в CONNECT, что есть те которые используют первый вариант кода...
и либо они не используют этот функционал, либо тогда получается, что только у меня эти ошибки вылазят...
может действительно, я со старой версией PHP остался?
Мой -CONNECT-
Windows 7(PHP 7.2) + Raspberry Pi(освещение на 1-Wire) + MP751(управление) + ESP8266(сенсоры) + LAN(сенсоры)
-=: Если вам помогло моё сообщение, нажмите кнопку "Поблагодарить за сообщение автора: Vovix" (кнопка Спасибо) справа! :=-
Аватара пользователя
sergejey
Site Admin
Сообщения: 4286
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 76 раз
Поблагодарили: 1559 раз
Контактная информация:

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение sergejey » Ср дек 09, 2015 11:08 am

Разве сейчас шаблоны поведения не отрабатывают одинаково "Включи" и "включи"? Мне казалось, что это давно было исправлено.
Собственно, в регулярных выражениях есть специальный модификатор "u", который очень помогает.
Можно заменить
preg_match('/включи/is',$original)
на
preg_match('/включи/uis',$original)
и всё начинает магическим образом работать :)
За это сообщение автора sergejey поблагодарил:
Vovix (Ср дек 09, 2015 11:53 pm)
Рейтинг: 1.16%

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Аватара пользователя
Vovix
Сообщения: 1155
Зарегистрирован: Пн янв 27, 2014 1:43 am
Откуда: г.Ижевск
Благодарил (а): 60 раз
Поблагодарили: 532 раза
Контактная информация:

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение Vovix » Ср дек 09, 2015 4:28 pm

sergejey писал(а):Разве сейчас шаблоны поведения не отрабатывают одинаково "Включи" и "включи"? Мне казалось, что это давно было исправлено.
Собственно, в регулярных выражениях есть специальный модификатор "u", который очень помогает.
Можно заменить
preg_match('/включи/is',$original)
на
preg_match('/включи/uis',$original)
и всё начинает магическим образом работать :)
как я и написал, сам шаблон - да, отрабатывает правильно и большую и маленькую буквы, но внутри - preg_match работает не правильно, если были модификаторы is.
Применить "u" попробую позднее!
Но обращаю внимание некоторых из первой 20-ки в CONNECT - проверьте, у вас там именно "is", может тоже уже не работает?
Мой -CONNECT-
Windows 7(PHP 7.2) + Raspberry Pi(освещение на 1-Wire) + MP751(управление) + ESP8266(сенсоры) + LAN(сенсоры)
-=: Если вам помогло моё сообщение, нажмите кнопку "Поблагодарить за сообщение автора: Vovix" (кнопка Спасибо) справа! :=-
Аватара пользователя
Vovix
Сообщения: 1155
Зарегистрирован: Пн янв 27, 2014 1:43 am
Откуда: г.Ижевск
Благодарил (а): 60 раз
Поблагодарили: 532 раза
Контактная информация:

Re: особенности UTF-8 при работе с регулярными выражениями

Сообщение Vovix » Ср дек 09, 2015 11:57 pm

проверил, прекрасно:
u (PCRE_UTF8)
Этот модификатор включает дополнительную функциональность PCRE, которая не совместима с Perl: шаблон и целевая строка обрабатываются как UTF-8 строки. Модификатор u доступен в PHP 4.1.0 и выше для Unix-платформ, и в PHP 4.2.3 и выше для Windows платформ. Валидность UTF-8 в шаблоне и целевой строке проверяется начиная с PHP 4.3.5. Недопустимая целевая строка приводит к тому, что функции preg_* ничего не находят, а неправильный шаблон приводит к ошибке уровня E_WARNING. Пятый и шестой октеты UTF-8 последовательности рассматриваются недопустимыми с PHP 5.3.4 (согласно PCRE 7.3 2007-08-28); ранее они считались допустимыми.
всё работает. Все заинтересованные лица - исправьте как рекомендовал Сергей на это - preg_match('/включи/uis',$original)
Мой -CONNECT-
Windows 7(PHP 7.2) + Raspberry Pi(освещение на 1-Wire) + MP751(управление) + ESP8266(сенсоры) + LAN(сенсоры)
-=: Если вам помогло моё сообщение, нажмите кнопку "Поблагодарить за сообщение автора: Vovix" (кнопка Спасибо) справа! :=-
Ответить