Два жадных квантификатора в одном и том же регулярном выражении

Если у меня есть неизвестная строка структуры:

"stuff I don't care about THING different stuff I don't care about THING ... THING even more stuff I don't care about THING stuff I care about"

Я хочу запечатлеть "вещи, которые меня волнуют", которые всегда будут после последнего появления THING. Существует вероятность появления 0 или более. Если есть 0 вхождений, то мне не о чем беспокоиться. Строка не может начинаться или заканчиваться THING.

Некоторые возможные строки:

"stuff I don't care about THING stuff I care about"

"stuff I don't care about"

Некоторые невозможные строки:

"THING stuff I care about"

"stuff I don't care about THING stuff I don't care about THING"


Мое текущее решение этой проблемы - использовать регулярное выражение с двумя жадными квантификаторами следующим образом:

if( /.*THING(.*)/ ) {
    $myStuff = $1;
}

Кажется, это работает, но мой вопрос о том, как два жадных квантификатора будут взаимодействовать друг с другом. Первый (самый левый) жадный квантификатор всегда "более жадный", чем второй?

По сути, я гарантированно не получу раскол, как показано ниже:

"stuff I don't care about THING"

$1 = "different stuff I don't care about THING even more stuff I don't care about THING stuff I care about"

По сравнению с расколом я хочу:

"stuff I don't care about THING different stuff I don't care about THING even more stuff I don't care about THING"

"stuff I care about"

3 ответа

Решение

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

В процессе сопоставления .*THING будет изначально соответствовать всему, вплоть до последнего вхождения THING

Если нет возможности сопоставить остальную часть шаблона, он будет возвращаться назад, становясь короче, и сопоставлять все, вплоть до последнего, кроме одного вхождения THINGи снова попытайтесь выполнить остальную часть шаблона

Однако остальная часть шаблона .* который всегда будет совпадать, потому что он будет соответствовать пустой строке

Следовательно, .*THING(.*) будет соответствовать вплоть до последнего вхождения THING, и будет соответствовать и захватить остальную часть строки

Обратите внимание, что . будет соответствовать чему угодно, кроме перевода строки. Если в вашем тексте могут быть символы новой строки, вы можете использовать /s модификатор, чтобы заставить это соответствовать чему-либо вообще

Также обратите внимание, что если шаблон не соответствует (потому что, скажем, нет THING в строке) тогда $1 останется без изменений. Он по-прежнему будет содержать все, что было установлено при последнем успешном сопоставлении с образцом. Это означает, что вы должны проверить состояние соответствия шаблона, прежде чем использовать значение $1

Вот мой дубль.

/^(?!THING).+THING((?:(?!THING).)+)$/

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

Редактировать: добавлена ​​проверка "Вещи" в начале строки.

РЕДАКТИРОВАТЬ: Wow, перечитывая ваши спецификации (что я действительно неправильно). Вы сказали, что если есть 0 случаев, то нет ничего, что меня волнует. Строка не может начинаться или заканчиваться THING.

Тогда ваше регулярное выражение в порядке. tripleee объяснил ситуацию хорошо.

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