Русские буквы (и другие не ASCII-символы) в строке

Issue #123 closed
Oleg Sychev repo owner created an issue

Originally reported on Google Code with ID 123 ``` Завожу issue чтобы обсуждения не терялись по е-мейлам и чатам.

Валерий, все-таки 1) если само выражение не содержит русских букв, точка с ними матчится? \w? Если русские буквы ввел студент при ответе на вопрос... 2) %full вместо %unicode пробовали? Что %unicode не заработает я догадывался, он UTF-16 использует а не 8. Хотя надо попробовать поискать функции перекодирования из 8 в 16 и тогда запустить. Но %full должен ориентироваться на локаль, он с русскими буквами в какой-то кодировке справится? ```

Reported by `oasychev` on 2012-05-09 19:34:40

Comments (35)

  1. Valeriy Streltsov

    ``` 1) Регекс \w+ совпал с двумя символами строки 'абвгд'. ```

    Reported by `vostreltsov` on 2012-05-12 12:14:37

  2. Valeriy Streltsov

    ``` php_preg_matcher вообще не сматчил эту строку на таком регулярном выражении. ```

    Reported by `vostreltsov` on 2012-05-12 12:18:36

  3. Valeriy Streltsov

    ``` Можно использовать iconv, будет что-то вроде такого:

    $utf16str = iconv('UTF-8', 'UTF-16', $utf8str);

    Не полезно ли, кстати, отцепить textlib и использовать для получения длин строк опять же iconv? ```

    Reported by `vostreltsov` on 2012-05-12 18:29:16

  4. Oleg Sychev reporter

    ``` Вы попробовали, насколько помогает сканеру перевод регекса через iconv перед сканнингом при включенном %unicode? При наличии русских букв в регексе... \w - отдельная песня... ```

    Reported by `oasychev` on 2012-05-13 15:41:50

  5. Oleg Sychev reporter

    ``` Странно, у меня Preg 2.1 сматчил весь русский алфавит с \w+ на PHP Preg matcher ```

    Reported by `oasychev` on 2012-05-13 19:44:55

  6. Valeriy Streltsov

    ``` Использование %full и %unicode не привело к положительным результатам. Пробовал кодировать сами исходники в разных кодировках, использовать файлы вместо stringstream. Английский символы лексятся нормально, русские - нет. ```

    Reported by `vostreltsov` on 2012-05-14 18:28:21

  7. Oleg Sychev reporter

    ``` Таки %unicode после преобразования регекса в utf16 через iconv пробовали?

    ```

    Reported by `oasychev` on 2012-05-15 07:50:07

  8. Valeriy Streltsov

    ``` Пробовал, iconv сам по себе работает нормально. ```

    Reported by `vostreltsov` on 2012-05-15 08:51:28

  9. Oleg Sychev reporter

    ``` %unicode если верить докам работает с utf16. Moodle - utf8. Значит по идее чтобы сканер нормально работал необходимо перекодировать строку с регексом из 8 в 16 перед тем как делать из нее stringstream чтобы сканер разбирал 16-ю кодировку.

    Вы этот вариант пробовали? ```

    Reported by `oasychev` on 2012-05-15 09:40:01

  10. Valeriy Streltsov

    ``` Я же упомянул про это еще в 3 комментарии. Я пробовал и так, и напрямую работу с файлом в UTF-16LE с BOM и без него, в общем все варианты на которые хватило фантазии. Меня смущают правила в лексере вида [a-zA-Z0-9_]... ```

    Reported by `vostreltsov` on 2012-05-15 13:05:15

  11. Oleg Sychev reporter

    ``` Меня тоже, но в рамках этого генератора лексеров лучшего найти не удалось.

    Надо бы еще поискать лексер-генераторы для PHP. Выбор, к сожалению, не так уж велик... ```

    Reported by `oasychev` on 2012-05-15 13:23:38

  12. Oleg Sychev reporter

    ``` Проблемы с матчингом \w и русских букв у матчеров разные.

    В случае PHP Preg матчера дело зависит от того, с каким флагом собран PHP и входящая в нее часть PCRE. Это вне контроля нашей программы в принципе.

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

    Надо проследить судьбу строки и понять, где она может портится. И попробовать использовать {} для доступа к элементу строки вместо []... ```

    Reported by `oasychev` on 2012-05-15 13:42:07

  13. Valeriy Streltsov

    ``` Я исправил jlex.php, заменив стандартные строковые функции на iconv'шные. Теперь нормально лексятся русские буквы, но понятно что нужно переписать все такие места.

    Мне кажется, нужно сами исходные файлы тоже сконвертировать в utf-8. Mercurial нормально это воспримет? Если например потом сливать клоны в разных кодировках... ```

    Reported by `vostreltsov` on 2012-05-16 12:18:23

  14. Oleg Sychev reporter

    ``` Коммитьте правки с использованием textlib в лексере для регулярных выражений и перевод тестов в utf-8 с русскими буквами (отдельными коммитами).

    С матчингом строк в юникоде надо разбираться отдельно. ```

    Reported by `oasychev` on 2012-05-16 13:21:07

  15. Oleg Sychev reporter

    ``` Изменил название на ту часть, которую осталось пофиксить. ```

    Reported by `oasychev` on 2012-05-17 13:52:01

  16. Valeriy Streltsov

    ``` Получилось матчить UTF-8 строку после замены функций во многих местах (хэндлер, узлы и т.д.).

    Предлагаю в хэндлере (или в матчере, не знаю где уместнее) ввести protected поле $textlib - оно используется в очень многих функциях. Аналогично и для абстрактного листа, там textlib требуется вообще в каждом match_innter. Это чтобы половина функций не начиналась с получения textlib'овского объекта...

    Что скажете? ```

    Reported by `vostreltsov` on 2012-05-19 19:42:19

  17. Valeriy Streltsov

    ``` На счет ctype_alnum.

    Я посмотрел на диапазоны символов, за исключением первых двух (Basic Latin и C1 Controls and Latin-1 Supplement) они целиком являются либо какими-то алфавитами, либо какими-то знаками (математическими и т. д.).

    Мне кажется можно просто сделать файлик, в котором задать глобальные массивы этих диапазонов. Определять алфавито-циферность не составит особых проблем. Также в этом файлике можно сделать функцию-аналог для ord(). ```

    Reported by `vostreltsov` on 2012-05-20 08:27:30

  18. Oleg Sychev reporter

    ``` Насчет поля с $textlib не возражаю. Можно и в хэндлере, хотя если применяется только для строки, а не регекса - то в матчере абстрактном логичнее...

    С ctype_alnum вам надо понимать историю. История такая: политика PCRE состояла в том, что \w и т.д. по умолчанию испольуют функции типа ctype_alnum в целях производительности - таблицы юникода большие и серьезно замедляют матчинг. У нас была идея следовать в этом же русле хотя бы ради совместимости. Но в Moodle исходная строка изначально юникодовская, поэтому функции могут быть к ней неприменимы. Что, собственно, и надо выяснить: если они работают криво, то имеем полное право перейти на юникод-свойства - в pcre.txt указаны юникод-эквиваленты для \w и т.д.; если работают - тогда возможно придется бороться за их сохранение... ```

    Reported by `oasychev` on 2012-05-20 19:41:35

  19. Valeriy Streltsov

    ``` Еще на счет текстлибовских функций, пока не добавил поле.

    Может, лучше сделать отдельный набор функций, типа qtype_preg_strlen или qtype_preg_ord в глобальном пространстве имен? Аналог ord() все равно нужен для лексера, так эти функции будут сконцентрированы в одном файле, например, preg_unicode.php? ```

    Reported by `vostreltsov` on 2012-05-21 11:10:22

  20. Oleg Sychev reporter

    ``` А чего не унаследоваться от textlib и добавить туда свою функцию для ord и прочего? Можно будет потом с мудловцами на этот счет поговорить... ```

    Reported by `oasychev` on 2012-05-21 14:48:26

  21. Valeriy Streltsov

    ``` В общем добавил файл preg_unicode.php. В нем основные строковые функции, включая юникодовский ord(), плюс закомментированые диапазоны - скорее всего пригодятся...

    В cross_tests_special_cases тест с юникодовской строкой и генерированием символа проходит, однако сам вопрос не работает - нужно и в его коде, наверное, менять все подобные функции. ```

    Reported by `vostreltsov` on 2012-05-22 17:56:43

  22. Oleg Sychev reporter

    ``` Почему не захотели наследоваться от textlib'а? Так легче этот код при необходимости в Moodle перенести будет...

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

    По поводу ctype_alpha и прочего в юникоде - логичнее использовать функции прямо для \w и т.д. Вот определение из pcre.txt, при юникоде \d any character that \p{Nd} matches (decimal digit) \s any character that \p{Z} matches, plus HT, LF, FF, CR \w any character that \p{L} or \p{N} matches, plus underscore

    ```

    Reported by `oasychev` on 2012-05-23 14:08:34

  23. Valeriy Streltsov

    ``` Ок, сделаю наследника - qtype_preg_unicode.

    Функции textlib, кстати, статические. Такими же сделаем и свои. Определяться с архитектурой, если я понял правильно, не за чем: можно ведь вызывать их, как, например, qtype_preg_unicode::ord().

    Перевод функций в вопросе тоже на мне? ```

    Reported by `vostreltsov` on 2012-05-23 15:24:20

  24. Oleg Sychev reporter

    ``` Да, раз там все статика, то и мы делаем также. Раньше там был синглтон, теперь они его заменили на статические функции. Если где остался синглтоновский код у нас (с вызовом через get_instance) его тоже надо исправить на статические функции.

    В вопросе тоже замените, если несложно... ```

    Reported by `oasychev` on 2012-05-31 11:17:51

  25. Valeriy Streltsov

    ``` На счет ctype_alnum: не работает на мудловских строках (пробовал на кириллическом и на французском символах).

    Все вызовы строковых функций, вроде бы, поправил (а также [] на substr в подсказках, а то оно показывало '�' как следующий символ:)).

    Но есть проблема, непонятно где возникающая: 1) При включенном exact matching вылетает исключение "Error: trying to do matching on regex with errors!" 2) При выключенном exact matching все нормально - как матчинг полностью правильных строк, так и генерация подсказок.

    Непонятно, как строка

    $for_regexp = '^(?:'.$for_regexp.')$';

    может все портить...

    ```

    Reported by `vostreltsov` on 2012-05-31 18:02:19

  26. Valeriy Streltsov

    ``` Проблема, судя по всему, в лексере. Оно нормально работает если в регексе только английские буквы. Как появляются буквы из юникода - специальные символы (доллар, скобки и т.д.) становятся обычными символами. ```

    Reported by `vostreltsov` on 2012-06-02 10:52:00

  27. Valeriy Streltsov

    ``` Пофиксил. Все опять же свелось к замене [] на substr в jlex.php.

    Теперь вопрос нормально справляется с китайскими регексами:) Осталось решить, что делать с \w... ```

    Reported by `vostreltsov` on 2012-06-02 12:57:10

  28. Oleg Sychev reporter

    ``` Есть предложение написать что-то типа qtype_preg_string реализуя интерфейс ArrayAccess чтобы подменить квадратные скобки. Ибо всюду вместо них писать substr - не самое приятное занятие... ```

    Reported by `oasychev` on 2012-06-02 18:10:40

  29. Valeriy Streltsov

    ``` Сделал эксперимент:

    class qtype_preg_string { private $str;

    public function toString() { return (string)$this->str; }

    public function construct($str) { $this->str = $str; }

    } $a = new qtype_preg_string('а'); $b = new qtype_preg_string('й'); $c = $a . $b; $q = new qtype_preg_string($c);

    var_dump($c); var_dump($q);

    Получилось, что тип $c - строка, а тип $q = qtype_preg_string.

    Мне кажется, разница не особо большая - создавать везде объект или писать substr... ```

    Reported by `vostreltsov` on 2012-06-09 09:51:25

  30. Oleg Sychev reporter

    ``` Объект создается намного реже, чем доступ к элементам (substr/[]). ```

    Reported by `oasychev` on 2012-06-09 11:45:11

  31. Valeriy Streltsov

    ``` Добавил класс строки и тесты для нее, изменения в vostreltsov-nfa-preg-22. ```

    Reported by `vostreltsov` on 2012-06-09 14:34:42

  32. Oleg Sychev reporter

    ``` Вы проверили, что [] работают через ArrayAccess, а не toString? Можно поставить echo в нужной функции и убедиться, что она вызывается... ```

    Reported by `oasychev` on 2012-06-12 07:43:22

  33. Valeriy Streltsov

    ``` Проверил. Да и тесты с китайскими символами фейлились бы, если через toString. P.S. Думаю, переводить весь код на использование этого класса будет удобнее в конце, когда смержим все ветки. ```

    Reported by `vostreltsov` on 2012-06-12 07:47:16

  34. Oleg Sychev reporter

    ``` Спасибо ```

    Reported by `oasychev` on 2012-07-19 08:47:12 - Status changed: `Done`

  35. Log in to comment