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

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

text to extract<number>

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

126
задан Rishabh 29 October 2016 в 10:42
поделиться

3 ответа

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

Рассмотрим ввод 101000000000100 .

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

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

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

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

149
ответ дан 24 November 2019 в 00:50
поделиться

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

<a></a>

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

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

16
ответ дан 24 November 2019 в 00:50
поделиться

О жадности и не жадности

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

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

Ссылки


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

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

При следующих входных данных:

eeeAiiZuuuuAoooZeeee

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

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

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.

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

Ссылки


Пример 2: От A до ZZ

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

eeAiiZooAuuZZeeeZZfff

Вот совпадения для приведенного выше ввода:

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

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

Похожие темы

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

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

160
ответ дан 24 November 2019 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: