Яка різниця між .*? і. * регулярні вирази?


142

Я намагаюся розділити рядок на дві частини за допомогою регексу. Рядок форматується наступним чином:

text to extract<number>

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


Відповіді:


172

Це різниця між жадними і не жадібними кванторами.

Розглянемо вхідні дані 101000000000100.

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

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

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

Див. Таблицю Quantifier Cheat Sheet .


Ах здорово, мені подобається, що останній нічого, крім знаку!
Дуг

1
Чи можете ви пояснити чи показати приклад того, чим жадібний ?відрізняється від нежадного ???
AdrianHHH

4
Звичайно. Для рядка "abc", регулярний вираз /\w\w?\w/відповідатиме повному рядку "abc"- бо ?жадібний. /\w\w??\w/лінивий - це буде лише відповідати "ab". Він буде відкликатись і збігатися, лише "abc"якщо не вдасться пізніше.
Кобі

184

На жадібний проти не жадібний

Повторення у регулярному вираженні за замовчуванням є жадібним : вони намагаються зіставити якомога більше повторень, і коли це не працює, і їм доводиться відслідковувати, вони намагаються одночасно відповідати меншій кількості повторень, поки збіг всього шаблону не буде знайдено. Як результат, коли матч нарешті відбудеться, жадібне повторення відповідатиме якомога більше повторів.

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

Список літератури


Приклад 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, які охоплюють деякі теми, які можуть зацікавити.

Одне жадне повторення може перевершити інше


1
Я мав на увазі сказати rubular.com, а не ideone.com. Іншим: не переглядайте цю посаду для мене, я зроблю це сам на наступній редакції разом з іншими прикладами. Не соромтеся давати відгуки, пропозиції тощо в коментарях, щоб я міг також їх включити.
полігенмастильні матеріали


4
Ця відповідь була додана до FAQ FAQ про регулярне вираження стека в розділі "Квантори> Більше про відмінності ..."
aliteralmind

Ця відповідь справді заслуговує на обрану відповідь !. Дуже дякую за ваше детальне пояснення.
masky007

Я додав тег не жадібний . Чому, тому що питання потребувало цього, а також тому, що воно приверне більше користувачів до цієї чудової відповіді. Іншими словами, якщо ви даєте чудову відповідь, і у відповіді використовується тег не у питанні, тоді додайте тег, оскільки ОП не знав, що тег шалено.
Хлопець Кодер

20

Скажімо, у вас є:

<a></a>

<(.*)>відповідатиме a></aде, як <(.*?)>би відповідав a. Остання зупиняється після першого матчу >. Він перевіряє наявність одного чи 0 відповідностей, за .*яким слідує наступний вираз.

Перший вираз <(.*)>не припиняється, коли відповідає першому >. Це триватиме до останнього матчу >.


це легше зрозуміти, ніж наведене вище пояснення.
Прометей
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.