Почему более длинный токен в чередовании не будет сопоставлен?

Я использую ruby ​​2.1, но то же самое можно повторить на сайте Rubular.

Если это моя строка:

儘管中國婦幼衛生監測辦公室制定的

И я делаю регулярное выражение с этим выражением:

(中國婦幼衛生監測辦公室制定|管中)

Я ожидаю получить более длинный жетон в качестве матча.

中國婦幼衛生監測辦公室制定

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

Насколько я знаю, это работает так, когда не на китайских иероглифах.

Если это моя строка:

foobar

И я использую это регулярное выражение:

(foobar|foo)

Возвращенный результат соответствия foobar, Если порядок другой, то соответствующая строка foo, Это имеет смысл для меня.

1 ответ

Решение

Ваше предположение, что регулярное выражение соответствует более длинному чередованию, неверно.

Если у вас есть немного времени, давайте посмотрим, как работает ваше регулярное выражение...

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

Есть два указателя, один на Шаблон:

(cdefghijkl|bcd)

Другой на вашей строке:

abcdefghijklmnopqrstuvw

Указатель на строку перемещается слева. Как только он может вернуться, он будет:

http://gyazo.com/ac652df1ed094be6c5d66c14a2728ac1.png

Давайте превратим это в более "последовательную" последовательность для понимания:

http://gyazo.com/386aecb351fc2eb34f9c5db269a66dab.png

Ваш foobar Пример это другая тема. Как я уже упоминал в этом посте:

Как работает регулярное выражение: конечный автомат всегда читает слева направо. ,|,, == ,, так как он всегда будет соответствовать только первому чередованию.

Это хорошо, Юниэдр, но как мне заставить его к первому чередованию?

Смотри! *

^(?:.*?\Kcdefghijkl|.*?\Kbcd)

Здесь есть демонстрация регулярных выражений.

Это регулярное выражение сначала пытается сопоставить всю строку с первым чередованием. Только если он потерпит неудачу полностью, он попытается сопоставить второе чередование. \K используется здесь, чтобы сохранить соответствие с содержимым позади конструкции \K,


* : \K поддерживается в Ruby с 2.0.0.

Прочитайте больше:





Ах, мне было скучно, поэтому я оптимизировал регулярное выражение:

^(?:(?:(?!cdefghijkl)c?[^c]*)++\Kcdefghijkl|(?:(?!bcd)b?[^b]*)++\Kbcd)

Вы можете увидеть демо здесь.

Другие вопросы по тегам