В чем разница между.*? и. * регулярные выражения?

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

text to extract<number>

Я использую (.*?)< а также <(.*?)> которые работают хорошо, но после прочтения в регулярное выражение, я только начал задаваться вопросом, зачем мне ? в выражениях. Я сделал это только после того, как нашел их на этом сайте, поэтому я не совсем уверен, в чем разница.

3 ответа

Решение

Это разница между жадными и не жадными квантификаторами.

Рассмотрим вход 101000000000100,

С помощью 1.*1, * является жадным - он будет соответствовать полностью до конца, а затем возвращаться, пока не сможет соответствовать 1, оставляя тебя с 1010000000001,
.*? не жадный * ничего не будет соответствовать, но затем будет пытаться сопоставить дополнительные символы, пока не совпадет 1, в конце концов, соответствие 101,

Все квантификаторы имеют не жадный режим: .*?, .+?, .{2,6}?, и даже .??,

В вашем случае аналогичная картина может быть <([^>]*)> - сопоставление чего-либо, кроме знака "больше чем" (строго говоря, оно соответствует нулю или большему числу символов, чем > между < а также >).

См. Шпаргалку квантификатора.

На жадных против не жадных

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

? поскольку квантификатор повторения меняет это поведение на нежадное, также называемое неохотным ( например, в Java) (а иногда и "ленивым"). Напротив, это повторение сначала будет пытаться сопоставить как можно меньше повторений, и когда это не сработает, и они должны вернуться назад, они начинают сопоставлять еще одно повторение за раз. В результате, когда совпадение, наконец, происходит, неохотное повторение будет соответствовать как можно меньшему количеству повторений.

Рекомендации


Пример 1: от А до Я

Давайте сравним эти две модели: A.*Z а также A.*?Z,

Учитывая следующий вход:

eeeAiiZuuuuAoooZeeee

Шаблоны дают следующие совпадения:

Давайте сначала сосредоточимся на том, что A.*Z делает. Когда это соответствовало первому A, .*, будучи жадным, сначала пытается подобрать как можно больше . насколько это возможно.

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

Так как Z не совпадает, двигатель возвращается, и .* должен соответствовать одному меньшему .:

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

Это происходит еще несколько раз, пока, наконец, мы не придем к этому:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

Сейчас Z может соответствовать, поэтому общий шаблон соответствует:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

Напротив, неохотное повторение в A.*?Z первые матчи как можно меньше . насколько это возможно, а затем принимать больше . как необходимо. Это объясняет, почему он находит два совпадения на входе.

Вот наглядное представление о том, что два шаблона совпали:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

Пример: альтернатива

Во многих приложениях два совпадения в приведенном выше вводе - это то, что является желательным, таким образом, неохотно .*? используется вместо жадных .* для предотвращения перепада. Однако для этого конкретного шаблона есть лучшая альтернатива, использующая класс отрицанных символов.

Шаблон A[^Z]*Z также находит те же два совпадения, что и A.*?Z шаблон для вышеуказанного ввода ( как видно на ideone.com). [^Z] это то, что называется отрицательным символьным классом: он соответствует всему, кроме Z,

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

Рекомендации


Пример 2: от А до Я.

Этот пример должен быть иллюстративным: он показывает, как шаблоны классов жадных, неохотных и отрицательных символов по-разному совпадают при одном и том же вводе.

eeAiiZooAuuZZeeeZZfff

Это совпадения для вышеуказанного ввода:

Вот визуальное представление того, что они совпали:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

похожие темы

Это ссылки на вопросы и ответы по stackru, которые охватывают некоторые темы, которые могут представлять интерес.

Одно жадное повторение может перерасти другое

Допустим, у вас есть:

<a></a>

<(.*)> будет соответствовать a></a в то время как <(.*?)> будет соответствовать a, Последний останавливается после первого матча >, Он проверяет на одно или 0 совпадений .* с последующим следующим выражением.

Первое выражение <(.*)> не останавливается при сопоставлении первого >, Это будет продолжаться до последнего матча >,

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