Regex не достаточно жадный

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

^.*[?&]U(?:RL)?=(?<URL>.*)$

В основном, он используется против URL-адресов, чтобы захватить ВСЕ после U = или URL = и вернуть его в URL-адрес

Итак, для следующего

http://localhost?a=b&u=http://otherhost?foo=bar

URL = http://otherhost?foo=bar

К сожалению, появился нечетный случай

http://localhost?a=b&u=http://otherhost?foo=bar&url=http://someotherhost

В идеале, я хочу, чтобы URL-адрес был " http://otherhost?foo=bar&url=http://someotherhost", вместо этого он просто " http://someotherhost"

EDIT: Я думаю, что это исправлено... хотя это не очень.

^.*[?&](?<![?&]U(?:RL)?=.*)U(?:RL)?=(?<URL>.*)$

Ответ 1

Проблема

Проблема не в том, что .* недостаточно жадна; это то, что другой .*, который появляется ранее, также жадный.

Чтобы проиллюстрировать проблему, рассмотрим другой пример. Рассмотрим следующие два шаблона; они идентичны, за исключением нежелания \1 во втором шаблоне:

              \1 greedy, \2 greedy         \1 reluctant, \2 greedy
              ^([0-5]*)([5-9]*)$           ^([0-5]*?)([5-9]*)$

Здесь у нас есть две группы захвата. \1 захватывает [0-5]*, а \2 захватывает [5-9]*. Здесь бок о бок сравнение того, что эти шаблоны соответствуют и захватывают:

              \1 greedy, \2 greedy          \1 reluctant, \2 greedy
              ^([0-5]*)([5-9]*)$            ^([0-5]*?)([5-9]*)$
Input         Group 1    Group 2            Group 1    Group 2
54321098765   543210     98765              543210     98765
007           00         7                  00         7
0123456789    012345     6789               01234      56789
0506          050        6                  050        6
555           555        <empty>            <empty>    555
5550555       5550555    <empty>            5550       555

Обратите внимание, что как жадный, как \2, он может только захватить то, что \1 еще не захватил первым! Таким образом, если вы хотите сделать \2 захватить как можно больше 5, вы должны сделать \1 неохотно, поэтому 5 на самом деле может захватить \2.

Приложения

Связанные вопросы


Исправление

Итак, применив это к вашей проблеме, вы можете исправить это двумя способами: вы можете сделать первый .* неохотным, поэтому (см. в rubular.com):

^.*?[?&]U(?:RL)?=(?<URL>.*)$

В качестве альтернативы вы можете просто полностью избавиться от части, связанной с префиксом (см. на rubular.com):

[?&]U(?:RL)?=(?<URL>.*)$