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

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

text to extract<number>

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


person Doug    schedule 19.06.2010    source источник
comment
см. также stackoverflow.com/questions/2301285/   -  person Cemafor    schedule 19.07.2013


Ответы (3)


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

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

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

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

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

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

person Kobi    schedule 19.06.2010
comment
Ах, здорово, мне нравится последнее из чего угодно, кроме знака ›! - person Doug; 19.06.2010
comment
Вы можете объяснить или показать на примере, чем жадный ? отличается от не жадного ??? - person AdrianHHH; 25.11.2015
comment
Конечно. Для строки "abc" регулярное выражение /\w\w?\w/ будет соответствовать полной строке "abc", потому что ? является жадным. /\w\w??\w/ ленив - будет соответствовать только "ab". Будет выполнен возврат и совпадение с "abc" только в том случае, если позже произойдет сбой. - person Kobi; 26.11.2015

О жадных и не жадных

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

? в качестве квантификатора повторения изменяет это поведение на не жадное, также называемое неохотным (, например, на 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

похожие темы

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

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

person polygenelubricants    schedule 19.06.2010
comment
Я имел в виду rubular.com, а не ideone.com. Другим: не пересматривайте этот пост за меня, я сделаю это сам в следующей редакции вместе с другими примерами. Не стесняйтесь оставлять отзывы, предложения и т. Д. В комментариях, чтобы я тоже мог их включить. - person polygenelubricants; 19.06.2010
comment
См. Также: stackoverflow.com/questions/3145023 / - person polygenelubricants; 30.06.2010
comment
Этот ответ был добавлен в Часто задаваемые вопросы о регулярных выражениях при переполнении стека в разделе «Квантификаторы» ›Подробнее о различиях ... - person aliteralmind; 10.04.2014
comment
Этот ответ действительно заслуживает того, чтобы его выбрали !. Большое спасибо за подробное объяснение. - person masky007; 03.10.2019
comment
Я добавил тег нежадный. Почему, потому что это было необходимо для вопроса, но также потому, что это привлечет больше пользователей к этому отличному ответу. Другими словами, если вы даете отличный ответ, и в ответе используется тег, которого нет в вопросе, тогда добавьте тег, потому что OP не знал, что тег был благородным. - person Guy Coder; 07.02.2020
comment
^festvox-[hikrdue][^n].*?[^8] отказался удалить какие-либо экземпляры с 8 дюймами. Этот ответ вызвал мыслительный процесс для использования ^festvox-[hikrdue][^n][^8]*, который все еще не работал, пока я не добавил $ i.w. ^festvox-[hikrdue][^n].*?[^8] (комментарий написан для меня как памятная записка) - person northern-bradley; 03.12.2020

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

<a></a>

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

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

person Simon    schedule 19.06.2010
comment
это легче понять, чем приведенное выше объяснение. - person Prometheus; 20.02.2020
comment
Вот какими должны быть объяснения. - person Mosia Thabo; 11.08.2020