Генерация следующего символа при наличии merged assertions

Issue #38 closed
Oleg Sychev repo owner created an issue

Originally reported on Google Code with ID 38

Классы-листья могут теперь иметь слитые с ними утверждения (массив).

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

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

Если ни один следующий символ не подходит (актуально главным образом для ^ и $, но
возможно и при a\bc) то следует вместо символа выдать сообщение (длинное, понятное)
через get_string (чтобы могло переводится), желательно с объяснением почему продолжить
нельзя...

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

Reported by oasychev on 2011-09-09 13:26:00

Comments (23)

  1. Valeriy Streltsov

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

    Может возникнуть ситуация, когда нет простого ассерта и может подойти символ любого типа - буква\цифра\другой символ. При этом один из вариантов может привести к удачному завершению генерации строки, а другой-нет. Поэтому нужно либо передавать в функцию нужный тип символа, либо возвращать массив символов разного типа, чтобы функция матчера пробовала разные пути. Как лучше сделать? (Мне кажется, массив предпочтительнее - тогда в функции матчера можно будет просто в цикле перебрать этот массив, не задумываясь о типе символов) ```

    Reported by `vostreltsov` on 2011-09-25 05:58:23

  2. Oleg Sychev reporter

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

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

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

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

    Я бы не хотел использовать массив, если это возможно, потому что они могут быть большими, особенно для Unicode. А \w и т.д. работают через функции (посмотрите метод match для preg_leaf_meta), как планируете массив составлять?! Если по другому не выйдет, нужна более сложная структура... ```

    Reported by `oasychev` on 2011-09-26 10:26:32

  3. Valeriy Streltsov

    ``` Да, проблема возникает для символьных классов, если дальше стоит ассерт. Пример - [a-z ?!]\b[a-z] Если в первом листе сгенерировать букву, будет тупик.

    они могут быть большими, особенно для Unicode.

    Я имел ввиду массив из 3 символов разного типа - буква\цифра\служебный символ - зачем больше? Нужно только добавить в нынешнюю реализацию character() для символьного класса проверку на алфавитно-циферность+ассерты и возвратить 3 символа вместо одного. ```

    Reported by `vostreltsov` on 2011-09-26 18:38:11

  4. Valeriy Streltsov

    ``` А у preg_leaf_meta функция character() вообще возвращает константные символы для разных подтипов листа. Там проблем не будет. При учете ассертов там получится либо тот же самый константный символ, либо сообщение о невозможности генерирования символа из-за нарушения ассерта...

    В общем, 3 символа будут возвращаться только из символьного класса, т.к. только там однозначно не определен тип символа и возможны варианты... ```

    Reported by `vostreltsov` on 2011-09-26 18:59:05

  5. Oleg Sychev reporter

    ``` По первому комменту - "зачем больше?" Рассмотрите вариант когда у вас в примере не a-z а слева a-l а справа h-v? Какую букву должен возврщать левый класс не зная правого?

    Насчет meta не согласен. Рассмотрите отрицательный случай \D\b[a-z.?] Как \D уложится в 3 символа? Все опять сложнее....

    А потенциально есть еще \L{} - unicode properties, там вообще труба.... ```

    Reported by `oasychev` on 2011-09-27 08:09:03

  6. Valeriy Streltsov

    ``` [a-l ?!]\b[h-v] Первый лист сгенерирует array('a','?'), второй array('h'). Функция матчера попробует пути "a\bh" и "?\bh" и возвратит второй путь. Если листы будут [a-l] и [h-v] то возвратится по букве и матчер выдаст сообщение о невозможности подобрать следующий символ...

    \D записывается как [^0123456789]. Тут можно возвратить вообще два символа - букву и какой-нибудь служебный символ, например, тот же array('a', '?').

    А что такое \L{} пока только разбираюсь... ```

    Reported by `vostreltsov` on 2011-09-28 16:14:53

  7. Oleg Sychev reporter

    ``` Ну а если [a-l ?!]\B[h-v] - \B - не граница слова? как первому классу догадываться, какая буква устроит второй? Не выкрутится так просто...

    \D технически не эквивалентно [^0123456789], в каких-то кодировках могут быть другие цифры. А уж \W вообще не предскажешь, буквы какой кодировки должны использоваться... Посмотрите на их реализацию, они работают через функции...

    Я бы подумал в сторону работы через match/character следующего узла, но этот код должен быть в character абстрактного класса

    P.S. С кросс-тестированием все готово?

    ```

    Reported by `oasychev` on 2011-09-29 09:32:54

  8. Valeriy Streltsov

    ```

    как первому классу догадываться

    Дык, именно поэтому и возвращается массив - потому что первый лист не может угадать. В случае \B возвратится то же самое, но пройдет уже "a\Bh". Задача листа - возвратить символы всех возможных ТИПОВ (причем максимум возвратится 3 символа), а уже матчер будет пробовать разные их комбинации. На счёт этого я точно уверен - я так делал в семестровой.

    А \D и \W можно же организовать цикл, вызывая проверку очередного символа на алфавито-циферность? Или это будет долго? Извиняюсь, если пишу глупость - с юникодом пока что не сталкивался...

    По кросс-тестированию: все замечания исправил. Ошибки вынесены в отдельный файл, классы переименованы. Единственное, непонятен пункт:

    4) при ассертах в тестах на матчинг и ошибках не забывать включать в сообщение имя

    тестируемого матчера какие ассерты имеются ввиду? ```

    Reported by `vostreltsov` on 2011-09-29 10:40:22

  9. Oleg Sychev reporter

    ``` В юникоде - сотни тысяч символов. Как бы циклом перебирать ... я бы не стал. Да и кодировка там своеобразная. И \s есть и еще много подобного. Там не 3 класса на самом деле.

    Насчет типов надо подумать, но шаткая это конструкция. Про \L{} точно можно забыть... И возможно не только про нее

    Ассерты имеются ввиду проверяющие правильность возвращаемых ответов. Но об этом лучше писать в соответствующей ветке ```

    Reported by `oasychev` on 2011-09-29 10:48:23

  10. Valeriy Streltsov

    ``` Предложение по поводу match\character.

    match() оставить таким же - в $length в любом случае записывать количество совпавших символов. Это же количество символов передавать в character, дав ему значение по умолчанию 0:

    public function character($length = 0)

    Вызовы для листьев кроме обратных ссылок править не придется. А обратная ссылка возьмет $length-й символ из подмаски... ```

    Reported by `vostreltsov` on 2011-10-23 15:09:55

  11. Valeriy Streltsov

    ``` Да, ещё нужно знать последний совпавший\сгенерированный символ для работы простых ассертов.

    public function character($previouschar, $length = 0)

    Так всё же придется править вызовы для всех листьев. ```

    Reported by `vostreltsov` on 2011-10-23 15:13:56

  12. Valeriy Streltsov

    ``` Ещё в функции consumes() я бы поменял возвращаемое значение. Чтобы на вопрос "сколько символов ты съедаешь?" она отвечала не "да\нет", а говорила сколько конкретно:) Это для вычисления длины оставшегося пути с обратными ссылками... ```

    Reported by `vostreltsov` on 2011-10-23 15:18:55

  13. Oleg Sychev reporter

    ``` Может быть лучше передать в character строку, позицию и длину? Мало ли что понадобится для след. символа... Так надежнее ИМХО. И заодно переименовать ее в next_character - поскольку все равно править вызовы, и роль ее теперь меняется.

    Насчет consumes сначала надо подумать - что она должна возвращать в случае, если обратная ссылка указывает на подмаску, совпадение с которой не завершилось до того, как отказала match ? Тогда при вычислении кратчайшего пути надо вовремя снабжать матчер информацией о кратчайшей длине совпадений с подмасками... ```

    Reported by `oasychev` on 2011-10-23 15:44:02

  14. Valeriy Streltsov

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

    надо вовремя снабжать матчер информацией о кратчайшей длине совпадений с подмасками...

    Само собой, и это несложно сделать. ```

    Reported by `vostreltsov` on 2011-10-23 17:21:10

  15. Oleg Sychev reporter

    ``` Комментарий к next_character не корректен: $pos это не позиция последнего верного символа, а позиция начала матчинга текущего узла (для обратной ссылки будут различными значениями). Позиция последнего верного символа равна $pos + $length

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

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

    Reported by `oasychev` on 2011-10-23 22:10:53

  16. Oleg Sychev reporter

    ``` Валерий, давайте договоримся что все изменения в базовом классе матчера будут предварительно согласованы со мной, а потом уже коммитится в код!

    И уж тем более недопустимо увязывать их в одном коммите с другими изменениями.

    Чтобы вы усвоили, пожалуйста, откатите последний коммит и сделайте коммит без изменений в preg_matcher.php (кроме добавления функции если она очень вам нужна). Не первый раз это делаете уже! Пора остановится, если просто объяснений не понимаете - будем учится на опыте...

    P.S. Не обижайтесь, вы молодец что работаете - лучше многих - но надо научится сначала думать и договариваться, потом делать. Напишите мне сначала свои идеи по общему устройству класса по-русски (возможно с примерами кода) и убедитесь что я не против, а потом уже кодируйте... В рамках вашего матчера у вас руки более развязаны. Но научитесь уважать области ответственности. Да и опыта у вас мало...

    Зачем вам например стандартизовывать внутреннее поведение матчеров, когда match в состоянии гораздо надежнее стандартизовать его снаружи?! И даже если они внутри стандартизованы, лишний уровень проверки не помешает. Зато проблемы матчера не повлияют на работу всего вопроса, а вы делаете его код более уязвимым...

    P.S. Вы проверку на количество узлов/переходов в свой матчер дописали? И добейтесь, чтобы она возвращалась так же в виде объекта ошибки (отдельный класс ошибки) и попадала в общий список ошибок (причем без вызова match, сразу после конструктора). Вот это сделать можно и нужно... ```

    Reported by `oasychev` on 2011-10-26 20:49:48

  17. Oleg Sychev reporter

    ``` Валерий, вы когда переименовывали next_character dfa подправили соответственно? Хотел вытянуть ваш код, но не вижу изменений в DFA.... Нельзя нарушать работу другого матчера (не забывайте перезапускать кросс-тесты для обоих)... ```

    Reported by `oasychev` on 2011-10-29 17:55:11

  18. Valeriy Streltsov

    ``` Да, переименовывал. В ревизии f7496a8331f1 видно, что изменен файл dfa_preg_matcher. Кросс-тесты я временно не запускаю для дфа, потому как он зависает на циклах нулевой длины(ждем фикс от Дмитрия). Родные тесты дфа проходит. ```

    Reported by `vostreltsov` on 2011-10-29 20:11:01

  19. Oleg Sychev reporter

    ``` Извиняюсь, не заметил. ```

    Reported by `oasychev` on 2011-10-29 20:28:55

  20. Oleg Sychev reporter

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

    Обсуждение реализации обратных ссылок должно идти в рамках issue 29.

    ```

    Reported by `oasychev` on 2011-11-11 17:16:28 - Labels removed: Milestone-Release2.1

  21. Oleg Sychev reporter
    Работа с ассертами пока отходит к Лепилкиной
    

    Reported by oasychev on 2013-08-30 19:42:21

  22. Oleg Sychev reporter
    Сделано, отлично.
    

    Reported by oasychev on 2015-03-01 22:28:21 - Status changed: Done

  23. Log in to comment