Последовательности типа \w \d \s внутри символьных классов должны корректно обрабатываться

Issue #57 closed
Oleg Sychev repo owner created an issue

Originally reported on Google Code with ID 57 ``` У нас имеются проблемы их обработки: - многие последовательности заменяются на значения, хотя должны обрабатываться через функции - \w и \W приводят к одинаковым действиям сканера, хотя обозначают, по идее, противоположные вещи

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

Reported by `oasychev` on 2011-11-20 21:41:51

Comments (25)

  1. Oleg Sychev reporter

    ``` Есть мнение, что \W \s и т.д. должны быть частью preg_leaf_charset, а не meta.

    Это дает легкую обработку их как внутри, так и вне класса (усложняется код charset, но он то как раз не сильно сложный), а также значительно более простые операции над листами (пересечение любых charsetов даст charset, а не набор узлов как сейчас). ```

    Reported by `oasychev` on 2011-11-29 08:09:18

  2. Oleg Sychev reporter

    ``` Символьные классы описываются последовательностями: \d \D \h \H \s \S \v \V \w \W \N

    \d \D \s \S \w \W должны быть реализованы через свойства preg_leaf_charser и поддерживаться через вызовы функций. \N эквивалентно точке (все кроме перевода строки). Остальные могут быть реализованы перечислением символов. Подробнее см. http://pcre.org/pcre.txt раздел Generic character types

    Последовательности видов \a \cx \e \f \n \r \t представляют собой отдельные символы и должны переводится в таковые. См. Non-printing characters того же документа.

    По идее надобность в preg_leaf_meta и сам класс должны исчезнуть.

    Дмитрий, прошу не тянуть с проектом переделки... ```

    Reported by `oasychev` on 2012-01-02 22:17:45

  3. Oleg Sychev reporter

    ``` Точнее preg_leaf_meta останется для эпсилонов и их аналогов типа ENDREG. ```

    Reported by `oasychev` on 2012-01-21 17:35:34

  4. Oleg Sychev reporter

    ``` Ввел дополнительные поля для этого.

    Юникод-свойства тоже надо в charset переводить... ```

    Reported by `oasychev` on 2012-01-21 18:03:11

  5. Former user Account Deleted

    ``` Идея такая: чарсет будет иметь строку содержащую перечислимые символы и массив флагов соответствующих не перечислимым (\w например), ключи этого массива будут заданы константами класса и будут являться именами функций которые проверяют символ на соответствие данному требования. Тогда можно будет, просто перебирая, этот массив foreach'ем и вызывая функцию имя которой хранится в ключе проверить символ. Пересечение чарсетов это пересечение строк и флажковых массивов массивов. Но как пересечь флажки? Как пересечь из \w \d ? Получится \w && \D понятное дело, но ведь в чарсете между флажками (и строкой тоже) имеются отношения "ИЛИ", если же сделать их через "И" и принимать символ соответствующий всем, то как быть с ситуациями где нужно "ИЛИ", [a\w\d]? Либо получится иерархическая структура либо можно сделать фокус. Я предлагаю такой фокус: флажок \w рассматривать как символ слова, кроме цифры, а цифру отдельно, \w из регекса превращать в \w || \d. Тогда все флажки будут непересекающимися, т.е. никакие два флажка не смогут принять один и тот же символ. Строку с перечисленными символами можно избавить от пересечения с флажками удалив лишние символы, ведь нет разницы принят символ дважэды или один раз, [ab@%\w] превратить в [@%\w] тогда для пересечения/вычитания/сложения и чего угодно строка станет таким же флажком, массивы флажков пересечь легко. В коде: class charset extend leaf { protected $string; protected $flags;$flags[self::<flagname>] = true если флажок установлен const w = 'is_alpha'; и т.д. }; ```

    Reported by `Xapuyc7` on 2012-03-11 18:15:42

  6. Oleg Sychev reporter

    ``` Проблему И/ИЛИ понял, буду думать. Важный вопрос - возможно ли более одного пересечения (т.е. пересечение уже ранее пересеченных элементов). Возможно придется хранить выражение - например в ДНФ (массив массивов, элементы внутренних массивов объединяются по И, а внешнего - ИЛИ). Т.е. array (array(d, space), array(w)) означает \d && [:space:]

    \w

    Можно запоминать, какие классы должны давать нулевое пересечение обязательно, это упростит дело....

    Вариант с особой обработкой \d \w мало что решает - см. issue про POSIX - классы. И есть еще Unicode properties, которые тоже проверяются вызовом функции. Так что в общем случае уходить от проблемы нельзя. ```

    Reported by `oasychev` on 2012-03-11 20:46:30

  7. Former user Account Deleted

    ``` Даже если возможно пересечение неограниченное количество раз, выражение состоящее из И/ИЛИ можно свести к двум уровням иерархии. Разве нет? На вскидку, да возможно. Мне кажется, что удобнее (для данного случая) использовать КНФ, т.е. объединять элементы внутренних массивов по ИЛИ а внешнего по И? И стоит ли делать двумерный массив или лучше выделить класс чарсета и класс пересечения чарсетов(но не пересечения пересечений)? О ДНФ/КНФ я тоже думал, мне показалось, что я нашел лучший вариант, показалось. ```

    Reported by `Xapuyc7` on 2012-03-11 21:00:39

  8. Oleg Sychev reporter

    ``` Два уровня можно получить при любом количестве пересечений.

    ДНФ или КНФ удобнее проверить на алгоритмах построения пересечения/разности - выйдут ли они одинаковыми или в какой-то ситуации проще будет. Ну и определения совпадения тоже...

    Я бы предпочел иметь один класс - или придется определять функцию пересечения пересечений, пересечения пересечения с чарсетом и т.д.). Гораздо удобнее иметь все одним классом, тем более что от двумерного массива в общем случае все равно не уйти видимо. ```

    Reported by `oasychev` on 2012-03-11 21:18:30

  9. Former user Account Deleted

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

    Reported by `Xapuyc7` on 2012-03-11 21:23:07

  10. Oleg Sychev reporter

    ``` Я не думаю что налицо серьезное усложнение кода при уменьшении количества классов. Один флаг - вполне разумный частный случай ДНФ/КНФ и никакого специального алгоритма обработки не требует.

    Единственное усложнение будет заключаться в том, что одиночный флаг будет записываться типа array(array(preg_leaf_charset::w)) - но это не так страшно, как дополнительные функции с дублированным кодом выполняющим одно и то же по сути действие.

    Если быть точным, то поскольку в оригинале все добавляется через ИЛИ то добавление в ДНФ будет выглядеть типа $xx->flags[] = array(preg_leaf_charset::w); В КНФ, кстати, немного сложнее...

    Единственно по хорошему для юнит-тестов нужно бы написать функцию эквивалентности чарсетов, с учетом разного порядка в ДНФ/КНФ....

    P.S. У нас будут вводиться новые флаги и т.д. Может быть это подходящий случай подогнать иерархию узлов под стандарты Moodle, имея qtype_preg_leaf_charset и т.д.? Когда-нибудь это все равно придется сделать...е ```

    Reported by `oasychev` on 2012-03-12 07:43:42

  11. Former user Account Deleted

    ``` Добавил проект нового чарсета, вся его структура есть, функции не реализованы (пишут implement before use!). Классов у меня все же получилось два: 1)класс одиночного флага, который получается так, что многое делает 2)класс чарсета, являющийся их контейнером. Одни и теже функции есть, но они будут делать разное: функции флага будут делать непосредственно свою работу, а функции контейнера будут обрабатывать их результаты в соответствии с ДНФ. Код в клоне. Таблицы пересечений и вычитаний составлю в ближайшее время. ```

    Reported by `Xapuyc7` on 2012-03-24 15:52:54

  12. Former user Account Deleted

    ``` Составил таблицы пересечений и вычитаний. В таблице вычитания из флажка которому посвящена строка вычитается флажок которому посвящен стобец. ??? означает что я не знаю что из этого получится, можно безболезненно заменить на false. false означает что одним флажком это не объять. Таблицы получились большие, даже если исключить из них( и из чарсета) дублирующиеся флажки (\w and [:word:], например) все равно останется немало, хотя загнать массив и можно радоваться, ведь это позволит не только избежать чрезмерного разрастания пересечений, но и сразу обнуруживать чарсеты которые не примут ничего, и соответствеено не делать переходов по ним. ```

    Reported by `Xapuyc7` on 2012-03-24 23:56:48

    <hr>

  13. Former user Account Deleted

    ``` Отредактировал таблицу. 1) исключил из неё повторы (\w [:word:] например) 2) исключил отрицательные флажки из таблицы пересечений и таблицы вычитаний (\D\W\S) 3) составил таблицу пересечений негативных флажка с негативными, она понадобится как для случая пересечния двух негативных флажков, так и для случая вычитания из позитивного флажка из негативного, в сущности это один случай. Остальные случаи

    преобразуются через таблицы пересечения позитивных флажков и вычитание позитивных

    флажков.

    В большей части случаев получается 1 флажок, реже то, что не может быть представлено одним флажком и пустое пересечение. Таким образом, считаю применение этих таблиц оправданым. ```

    Reported by `Xapuyc7` on 2012-03-25 13:12:06

    <hr>

  14. Oleg Sychev reporter

    ``` По коду: 1) а что, у нас charset кроме флагов, ничего уже не содержит? А куда просто символы девать? 2) все потомки preg_node рассчитывались на то, что они имеют открытые public - поля. Насчет флагов можно подумать, но если поля защищены - то в конструкторе они должны заполняться полностью. А так у вас и способа то нет им что-либо присвоить... 3)\w включает буквы, цифры и подчеркивания - а у вас, если не ошибаюсь, минус вместо подчеркивания... 4) add_flag - может быть добавить к названию как добавить, т.е. add_conjuncted_flag или add_disjuncted_flag или что-нибудь в этом роде... 5) юникод-свойство если уж хранить arg то наверное '/\p{'.$prop.'}/' А называть имя функции "value" - довольно странное занятие. Нужно конкретнее определиться со значением этих аргументов. 6) Еще должна быть функция consumes, которая вычисляется не совсем очевидным образом учитывая что ассерты тоже могут быть флагами... ```

    Reported by `oasychev` on 2012-03-25 17:13:30

  15. Oleg Sychev reporter

    ``` По таблице 1) не согласен с false для ascii Возьмите таблицу символов и посмотрите. Например цифры - разве они не все от 0 до 127? Или \s ? 2) Наборы символов, не являющиеся флагами, мы всегда сможем хранить просто набором (возможно негативным), или они тоже должны участвовать к ДНФ?

    P.S. DNF - это плохой комментарий! Человек, незнакомый с нашими идеями, его не поймет. Напишите что логическая функция от флагов в ДНФ (не аббревиатурой, а словами) ```

    Reported by `oasychev` on 2012-03-25 18:32:26

  16. Oleg Sychev reporter

    ``` И еще таблица могла бы чаще использовать set. Например при пересечении xdigit с alpha - разве не ясно, какой будет set? ```

    Reported by `oasychev` on 2012-03-25 18:33:26

  17. Former user Account Deleted

    ``` 1)просто символы это частный случай флага, ведь с ними можно обращаться как с флагом, а дополнительные возможности обращения с ними остаются классу флага, тогда как контейнер-чарсет не интересуется типом флага 2)Согласен, буду думать о конструкторах, сделать флаги пабликом, впринципе, можно, главное самим помнить о их сложности и не трогать без нужды, но протектид мне более симпатичен, в данном случае. 3)Ой! Шифт не нажался :) 4)возможно нужны две такие такие функции, добавить функцию не сложно, эту переименую, вторую добавлю если понадобится. 5)так ведь \p{<property>} прилетит из лексера, флагу останется окружить его / /, разве нет? value для случая набора символов там будет именно значение, а ведь валуе не используется для пропертей, только арг, так зачем две переменные? может их в одну свести и назвать её <пока не придумал как>, зачем классу лишнее свойство? 6)вычисляется она просто, но у неё будет три результата: да нет, может так и может сяк. Последнее не может образоваться ни придти из регекса ни образоваться при мержинге ассертов, и этого не будет при построении автомата, если смержить ассерты до построения. Его наверное стоит запретить. Можно всегда глотать символ, можно никогда не глотать символ, но нельзя решать это в момент матчинга.

    1)0123456789 все лежат в аски, но мы ведь не делаем их перечислимыми именно потому что могут быть экзотические цифры. Где будут лежать экзотические цифры? до 127 или после? Я не знаю. 2)[^a1] & \D | [^ T] & \S, например, я не представляю, как отсюда вытащить единый набор символов, думаю, что должны учавствовать в ДНФ.

    ПС) комментарии перепишу

    И) xdigit это 0123456789abcdefABCDEF для любой локали? тогда зачем на xdigit? Перечислимый набор получается. ```

    Reported by `Xapuyc7` on 2012-03-25 19:41:23

  18. Oleg Sychev reporter

    ``` 1) а, у вас там во флаге путаница с полями. Давайте называть их по назначению, лучше лишнее поле завести чем писать многострочные списки комментариев, что обозначает данное поле при каком типе флага... Исправляем бардак. 5) я бы по из лексера передавал только property без \p{} потому как во первых, неизвестно зачем еще оно может пригодиться кроме матчинга, во-вторых - \P это, как обычно, отрицание, оно должно перейти в отдельное свойство. 6) надо исследовать, при какой ситуации возможно "и так и сяк". Пример ДНФ и как оно может образоваться. Ассерты будут участвовать в ДНФ при построении ДКА, иначе у вас корректно они не обработаются - если не будут смержены предварительно, хотя там тоже могут возникнуть проблемы... 7) по POSIX-классам в пересечении с ASCII http://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes xdigit может быть и не одинакова по локалям, но ASCII набор (0-127) от локали не меняется, локаль обычно меняет набор 128-255. Поэтому пересечения POSIX/ASCII определить можно, вот разность уже имеет риск быть зависимой от локали.

    Обратите внимание что вполне возможны выражения типа [x-z[:digit:]] а также отрицания [:^alpha:] Собственно POSIX классы поддерживаются PCRE только внутри символьных классов... ```

    Reported by `oasychev` on 2012-03-25 20:12:31

  19. Former user Account Deleted

    ``` 1)Ну лишнее так лишнее. 5)опять же, не проблема. 6)Пример ДНФ ^ | a. Если мержить ассерты до построения автомата, то образоваться не может никак, это наше спасение. Ведь "и так и сяк" просто в лоб нельзя ни мержить ни использовать, их можно было бы разбивать, но все равно проблемы с точки зрения ЧСК. 7)Допустим можно, каков риск запутаться в символах закорючках? Для не закорючных случаев можно. Сделаю.

    [x-z[:digit:]] не проблема. :^alpha: или [^[:alpha:]]? хотя и то и то не есть проблема. Я ведь составил таблицы так, чтобы они покрыли все случаи пересеченипя ++ +- -+ --, а вычитание выражается через пересечение и отрицание. ```

    Reported by `Xapuyc7` on 2012-03-25 20:36:35

  20. Oleg Sychev reporter

    ``` 1) поля называть: charset, uniprop и т.д - чтобы по названию было ясно, что они содержат 6) А чем вам поможет мержинг? Там у вас все равно получится что-нибудь типа a при условии ^. Тогда вам смерженные ассерты нужно будет в состав индивидуального флага водить. Полностью извести можно только \b - и то с ограничениями... 7) Какой риск запутаться в закорючках копируя их из википедии? Ну зависит от степени внимательности...

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

    ```

    Reported by `oasychev` on 2012-03-28 09:38:25

  21. Oleg Sychev reporter

    ``` И если оно все не проблема - то где хотя бы исправленные классы чарсета/флага? ```

    Reported by `oasychev` on 2012-03-28 09:39:29

  22. Oleg Sychev reporter

    ``` добавить кросс-тесты на \w \d \W и т.д. внутри символьного класса ```

    Reported by `oasychev` on 2012-07-23 09:07:58

  23. Log in to comment