В чем разница между .*?и. * регулярные выражения? - PullRequest
117 голосов
/ 19 июня 2010

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

text to extract<number>

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

Ответы [ 3 ]

148 голосов
/ 19 июня 2010

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

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

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

Ссылки


Пример 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: от A до ZZ

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

eeAiiZooAuuZZeeeZZfff

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

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

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

Похожие темы

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

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

140 голосов
/ 19 июня 2010

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

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

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

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

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

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

16 голосов
/ 19 июня 2010

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

<a></a>

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...