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

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

Во время работы над упражнением codewars «Вы имели в виду…?» в Javascript я пытался подсчитать, сколько символов в слове 1 появляется в слове 2. Я пытаюсь сопоставить каждый символ как свою собственную группу совпадений, чтобы позже я мог подсчитать количество успешных совпадений в массиве и использовать это, чтобы узнать, насколько похожи два слова.

Пожалуйста, не давайте мне советов, как решить задачу codewars, просто помогите мне понять, что здесь происходит.

Я старался:

'berry'.match(/(c?)(h?)(e?)(r?)(r?)(y?)/)

и не нашел совпадений

> ["", "", "", "", "", "", ""]

Это загадка для меня. При поиске Regular-expressions.info ? (сделать предшествующий символ необязательным) является жадным, поэтому, хотя для регулярного выражения нет допустимых совпадений, не должна ли она сначала превзойти жадную версию? Я ожидал этого:

> ["", "", "", "e", "r", "r", "y"]

Другие вещи, которые я пробовал: - Cherry Match Cherry работает, как я и ожидал

'cherry'.match(/(c?)(h?)(e?)(r?)(r?)(y?)/)
> ["cherry", "c", "h", "e", "r", "r", "y"]

Cherl Match Cherl работает так, как я и ожидал

'cherl'.match(/(c?)(h?)(e?)(r?)(r?)(y?)/)
> ["cher", "c", "h", "e", "r", "", ""]

И если я уберу ? из финального y, он тоже будет работать как положено:

'berry'.match(/(c?)(h?)(e?)(r?)(r?)(y)/)
> ["erry", "", "", "e", "r", "r", "y"]

Так почему же добавление ? к конечному y означает, что я больше не вижу совпадающих символов?

Хотя я пробовал это в JS, я получаю то же самое в PY и PCRE.


person samjewell    schedule 19.02.2016    source источник
comment
? означает "один или ничего" и всегда соответствует действительности: если ничего не найдено, это считается совпадением. Он жаден до тех пор, пока пытается найти что-то первым (вместо противоположного квантификатора ленивости: постарайтесь удовлетвориться ничего).   -  person Jan    schedule 19.02.2016
comment
Вы не использовали /g в JS, поэтому получили одно совпадение: пустое место в начале строки. Взгляните на эту демонстрацию   -  person Wiktor Stribiżew    schedule 19.02.2016
comment
Спасибо Ян, Виктор - в частности Виктор - это имеет смысл. Таким образом, механизм регулярных выражений работает слева направо в строке, пытаясь найти совпадение, и без флага g он находит совпадение с нулевыми символами в самом начале строки.   -  person samjewell    schedule 19.02.2016


Ответы (1)


Так почему же добавление ? к конечному y означает, что я больше не вижу совпадающих символов?

Шаблон, который вы использовали в начале — /(c?)(h?)(e?)(r?)(r?)(y?)/может соответствовать пустой строке, поскольку все подшаблоны являются необязательными (т. е. могут соответствовать нулю вхождений). Когда вы ищете только одно совпадение (скажем, с String#match в JavaScript), вы всегда получите совпадение, которое находится в самом начале строки (поскольку в большинстве случаев механизм регулярных выражений анализирует строку слева направо), либо пустая строка (если первый символ не может соответствовать первому подшаблону), либо некоторая подстрока, если совпали начальный или все подшаблоны.

Итак, berry начинается с b. /(c?)(h?)(e?)(r?)(r?)(y?)/ начинается с необязательного c, поэтому b не может сопоставляться с c, и это не удается. b не может быть сопоставлено ни с h, ни с e, ни с r, ни с другим r, ни с y. Обратите внимание, что если вы измените последнее y? на b?, вы получите b в матче.

Если вы не используете флаг /g (глобальный) в регулярном выражении JS, движок будет проверять только одно совпадение. Он найдет его в начале - пустую строку, вернет ее и на этом закончит. Если вы используете /g, он проверит все местоположения, и второе совпадение даст вам результат, который вы хочу. Однако при использовании String#match() с регулярным выражением на основе /g вы потеряете захваченные подстроки. Используйте RegExp#exec(), чтобы получить доступ к этим подсовпадениям.

Обратите внимание, что /(c?)(h?)(e?)(r?)(r?)(y)/ дает вам совпадение, потому что последнее y является обязательным и шаблон больше не может соответствовать пустой строке. Таким образом, когда движок видит b в berry, он не находит совпадения, переходит к проверке следующего местоположения перед e и находит там совпадение. Таким образом, в этой ситуации нет необходимости в /g.

person Wiktor Stribiżew    schedule 19.02.2016