Странное поведение NFA-матчера при частичном совпадении при возврате подмасок
Originally reported on Google Code with ID 71 ``` Выражение [+\-]?([0-9]+)?\.([0-9]+)
Если я ввожу 12 т.е. 2 и более цифры без точки, она возвращает совпадение с первой подмаской.
Но если я ввожу 1 т.е. одну цифру - совпадения с первой подмаской нет.
В чем разница? ```
Reported by `oasychev` on 2011-11-29 19:39:27
Comments (16)
-
reporter -
``` Похоже, неправильно строится автомат для + ```
Reported by `vostreltsov` on 2011-11-29 20:20:26
<hr>
- *Attachment: [automaton1.jpg](https://storage.googleapis.com/google-code-attachments/oasychev-moodle-plugins/issue-71/comment-2/automaton1.jpg)*
-
reporter ``` Нахождение квантификатора в квантификаторе представляет проблему для многих матчеров (backtracking тоже с этим делом мучался...).
Для полной проверки работоспособности этого дела необходимо составить набор кросс-тестов.
Принципиальных параметра, влияющих на структуру автомата, у квантификатора два: возможность совпадения 0 раз и возможность совпадения бесконечное количество раз. Итого имеем 4 вида квантификаторов.
Два квантификатора - один в другом - дают 4*4=16 видов регулярных выражений для тестирования. Размер совпадения с внутренним квантификатором необходимо проверить с помощью захвата подмаски.
Совпадения должны удовлетворять условиям, изложеным в http://laurikari.net/ville/regex-submatch.pdf на стр. 7
Когда все 16 тестов пройдут - переводим в Fixed.
```
Reported by `oasychev` on 2011-11-29 20:47:07
-
reporter ``` Принцип построения тестирующих строк: повторяемый символ встречается 0 раз 1 раз среднее (больше левой и меньше правой границы внутреннего квантификатора) максимальное внутри (равно правой границе внутреннего квантификатора) больше максимального внутри
Соответственно левую границу для ненулевых лучше выбирать больше 2, правую для конечных - так чтобы правая минус левая было не меньше чем 3 или 4.
Разумеется, не к каждому квантификатору применимы все случаи... ```
Reported by `oasychev` on 2011-11-29 21:12:31
-
``` На мой взгляд, PCRE немного нелогичен в некоторых ситуациях (по крайней мере в нашем случае - задание правильного ответа). Например, (ab|abc) на строке 'abc' захватит только первые два символа - я так понимаю, первое из трех правил той pdf'ки в действи... ИМХО, не нужно следовать такому правилу и захватывать самое длинное совпадение. И вообще, немного непонятно, как автомат проходить по "левым" путям вперед "правых" - рекурсивно, чтоли? Тогда в чем отличие от backtracking? ```
Reported by `vostreltsov` on 2011-11-30 18:17:37
-
reporter ``` Оно и есть backtracking. Я вам разве на PCRE ссылку давал? ```
Reported by `oasychev` on 2011-11-30 19:16:12
-
reporter Reported by `oasychev` on 2011-12-23 10:45:47 - Labels added: Milestone-Release2.2 - Labels removed: Milestone-Release2.1
-
``` Не получается соблюдать требования POSIX при нашей стратегии "меньше символов до полного совпадения".
Все тот же тест: (?:a|b)*abb$ на строке 'ab' - дает опять 3 символа до завершения, и это соответствует правилу leftmost-longest... ```
Reported by `vostreltsov` on 2012-02-11 10:58:28
-
reporter ``` Разумеется. Мы с вами говорили уже в другом issue что первое правило (leftmost-longest) мы подменяем, у нас другие цели. А вот второе и третье - про подмаски и квантификаторы - соблюдаем, они связаны уже с распределением символов внутри совпадения... ```
Reported by `oasychev` on 2012-02-11 16:31:36
-
``` В общем что я сделал. Приоритеты действительно оказались не нужны, добавились проверки в worse_than (пока что код не вытолкнут). Правило leftmost говорит о том, что захват подмаски k приоритетнее, чем захват k+n - это проверяется в цикле по всем подмаскам (точно так же как и в исходниках TRE). Аналогично проверяется и repeating rule - если при прочих равных условиях подмаска встречена позже, выбирается последний вариант.
Вот как сейчас выглядят проверки:
4. Longest match if ($other->length[0] > $this->length[0]) { return true; } elseif ($this->length[0] > $other->length[0]) { return false; } Leftmost rule foreach ($this->index_first as $key=>$value) { if ($key !== 0 && $value === qtype_preg_matching_results::NO_MATCH_FOUND && $other->index_first[$key] !== qtype_preg_matching_results::NO_MATCH_FOUND) { return true; } else if ($key !== 0 && $value !== qtype_preg_matching_results::NO_MATCH_FOUND && $other->index_first[$key] === qtype_preg_matching_results::NO_MATCH_FOUND) { return false; } } Repeating rule foreach ($this->length as $key=>$value) { if ($key !== 0 && $this->index_first[$key] < $other->index_first[$key]) { return true; } else if ($key !== 0 && $this->index_first[$key] > $other->index_first[$key]) { return false; } }
После такой доработки тесты из matching strategy (после исправления некоторых ошибок) проходят. Выталкивать этот код? ```
Reported by `vostreltsov` on 2012-02-12 15:18:44
-
reporter ``` Подождите.
Есть два вопроса: 1) вы достигли результата Вилли - количество состояний матчинга не больше количества состояний автомата? 2) эти проверки должны быть не в qtype_preg_matching_results::worse_than - а в вашем наследнике (переопределенной операции). Хорошо бы придумать вариант чтобы вызвать родительскую функцию, но тогда нужно как-то добавить в нее возможность возвращать что эквивалентны по предыдущим правилам... ```
Reported by `oasychev` on 2012-02-12 18:18:41
-
``` 1) Нет, я еще думаю над этим. Пытался делать выбор по этим правилам, результаты получились не совсем адекватные. 2) Согласен, если можете - сделайте возвращаемое значение функции. Я по этой причине и не выталкиваю пока что свой код... Хотя, с другой стороны, в родительской функции такие проверки тоже не лишние - мало ли что вернет другой матчер? А это - проверка стандартных для всех условий в централизованном месте... ```
Reported by `vostreltsov` on 2012-02-13 11:57:53
-
reporter ``` 1) По Вилли надо говорить всерьез, возможно при личной встрече и когда я сам уже его почитаю возможно. Сейчас это быстро не выйдет - завален огромным количеством орг. работы по кафедре в связи с проверками. 2) Есть идея сделать параметр по ссылке &$isequal для возврата эквивалентности - хотя сейчас можно проверить вызвав дважды с разными $orequal - но это неэффективно.
В родительском классе worse_than используется в других целях - при сравнении совпадений с разных позиций - я пока не уверен, что эти проверки имеют смысл при сравнении совпадения с разных позиций, они только для вариантов одной позиции. ```
Reported by `oasychev` on 2012-02-13 12:53:27
-
reporter ``` Валерий, это уже Fixed? ```
Reported by `oasychev` on 2012-04-05 15:30:13
-
Reported by `vostreltsov` on 2012-04-05 16:10:59 - Status changed: `Fixed`
-
reporter Reported by `oasychev` on 2012-04-07 04:23:57 - Status changed: `Done`
- Log in to comment
Reported by `oasychev` on 2011-11-29 19:39:55