Що означають "ледачий" та "жадібний" у контексті регулярних виразів?


Відповіді:


643

Жадібні будуть споживати якомога більше. З http://www.regular-expressions.info/repeat.html ми бачимо приклад спроби співставити теги HTML <.+>. Припустимо, у вас є наступне:

<em>Hello World</em>

Ви можете подумати, що <.+>( .означає, що будь-який символ, що не є новим рядком і +означає один або кілька ), відповідатиме лише тому <em>і тому </em>, коли насправді воно буде дуже жадібним, і піде від першого <до останнього >. Це означає, що він буде відповідати <em>Hello World</em>замість того, що ви хотіли.

Зробити це лінивим ( <.+?>) запобіжить цьому. Додавши ?після +, ми говоримо, щоб це повторилося якомога менше разів , тому перше, >що трапляється, - це те, де ми хочемо зупинити відповідність.

Я б закликав вас завантажити RegExr , чудовий інструмент, який допоможе вам вивчити регулярні вирази - я використовую його постійно.


2
тож якщо ви користуєтесь жадібними, у вас буде 3 (1 елемент + 2 теги) збігів або лише 1 збіг (1 елемент)?
ajsie

10
Він би відповідав лише 1 раз, починаючи з першого < і закінчуючи останнім > .
Сампсон

3
Але зробити його ледачим було б двічі, давши нам і тег відкриття, і закриття, ігноруючи текст між ними (оскільки він не відповідає виразу).
Сампсон

Ще один чудовий інструмент, який я завжди використовую: debuggex.com Він також має функцію "Embed on StackOverflow".
Рон ван дер Хайден

8
Просто додамо, що існує також жадібний спосіб <[^>]+> вирішити
alanbuchanan

301

"Жадібний" означає відповідність найдовшої струни.

"Ледачий" означає збіг найкоротшого можливого рядка.

Наприклад, жадібні h.+lсірники 'hell'в, 'hello'але ліниві h.+?lсірники 'hel'.


96
Блискучий, такий ледачий припиниться, як тільки буде виконано умову l, але жадібний означає, що він припиниться лише після того, як умова l вже не буде задоволена?
Ендрю S

3
Для всіх людей, які читають публікацію: жадібні чи ледачі квантори не відповідають собі найдовшій / найкоротшій можливій підрядковій лінії. Вам доведеться використовувати або загартований жадібний маркер , або використовувати не-регулярний підхід.
Wiktor Stribiżew

3
@AndrewS Не збивайте з пантелику подвійний ll у прикладі. Він досить ледачий буде відповідати найкоротшій можливій підрядці, тоді як жадібний буде відповідати найдовшому. Жадібні h.+lсірники 'helol'в, 'helolo'але ліниві h.+?lсірники 'hel'.
в.шашенко

3
@FloatingRock: Ні. x?Означає xнеобов'язково, але +?це інший синтаксис. Це означає, що перестаньте доглядати, коли ви знайдете щось, що відповідає - ліниве відповідність.
slebetman

1
@FloatingRock: Щодо того, як ви розмежовуєте різні синтаксиси, простий: ?означає необов’язковий та +?означає лінивий. Тому \+?засоби +необов’язкові.
slebetman

113
+-------------------+-----------------+------------------------------+
| Greedy quantifier | Lazy quantifier |        Description           |
+-------------------+-----------------+------------------------------+
| *                 | *?              | Star Quantifier: 0 or more   |
| +                 | +?              | Plus Quantifier: 1 or more   |
| ?                 | ??              | Optional Quantifier: 0 or 1  |
| {n}               | {n}?            | Quantifier: exactly n        |
| {n,}              | {n,}?           | Quantifier: n or more        |
| {n,m}             | {n,m}?          | Quantifier: between n and m  |
+-------------------+-----------------+------------------------------+

Додати? до кількісного показника, щоб зробити його нечестивим, тобто лінивим.

Приклад:
Тест рядок: StackOverflow
жадібні вираз рег : s.*oвихід: stackoverflo ш
ледачим виразом рег : s.*?oвихід: stacko verflow


2
не ?? дорівнює ? . Так само чи не {n}? еквівалентно {n}
номер945

5
@BreakingBenjamin: ні ?? не еквівалентно ?, коли у нього є вибір повернути 0 або 1 виникнення, він вибере альтернативу 0 (ледачий). Щоб побачити різницю, порівняйте re.match('(f)?(.*)', 'food').groups()з re.match('(f)??(.*)', 'food').groups(). В останньому, (f)??він не буде відповідати провідному 'f', хоча це міг. Отже, 'f' буде відповідати другій '. *' Групі захоплення. Я впевнений, що ви можете сконструювати приклад із '{n}?' теж. Справді, ці два дуже рідко використовуються.
smci

55

Жадібний означає, що ваш вираз буде відповідати якомога більшій групі, лінивий означає, що він відповідає найменшій можливій групі. Для цього рядка:

abcdefghijklmc

і цей вираз:

a.*c

Жадібний сірник відповідатиме всій струні, а лінивий - лише перший abc.


16

Наскільки мені відомо, більшість двигунів-регексів за замовчуванням жадібні. Додайте знак запитання в кінці кількісного показника, це дозволить лінивому збігу.

Як в коментарі згадував @Andre S

  • Жадібний: продовжуйте пошук, поки умова не буде виконана.
  • Ледачий: припиніть пошук, коли умова виконана.

Зверніться до прикладу нижче щодо того, що жадібно, а що ліниво.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String args[]){
        String money = "100000000999";
        String greedyRegex = "100(0*)";
        Pattern pattern = Pattern.compile(greedyRegex);
        Matcher matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm greeedy and I want " + matcher.group() + " dollars. This is the most I can get.");
        }

        String lazyRegex = "100(0*?)";
        pattern = Pattern.compile(lazyRegex);
        matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm too lazy to get so much money, only " + matcher.group() + " dollars is enough for me");
        }
    }
}


Результат:

I'm greeedy and I want 100000000 dollars. This is the most I can get.

I'm too lazy to get so much money, only 100 dollars is enough for me

9

Взято з www.regular-expressions.info

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

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


6

З регулярного вираження

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

Використовуючи лінивий квантор, вираз спочатку намагається мінімально відповідати.


4

Жадібна відповідність. Типова поведінка регулярних виразів має бути жадібною. Це означає, що вона намагається витягти якомога більше, поки вона не відповідає шаблону, навіть коли менша частина була б синтаксично достатньою.

Приклад:

import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']

Замість того, щоб відповідати до першого появи ">", він витягнув весь рядок. Це жадібна за замовчуванням або поведінка «регулярно приймати все».

Ледача відповідністьЗ іншого боку, "займає якнайменше". Це можна досягти, додавши в ?кінці шаблону а.

Приклад:

re.findall('<.*?>', text)
#> ['<body>', '</body>']

Якщо ви хочете отримати лише першу відповідність, замість цього скористайтеся методом пошуку.

re.search('<.*?>', text).group()
#> '<body>'

Джерело: Приклади Python Regex


3

Жадібний означає, що він буде споживати ваш візерунок, поки не залишиться жоден з них і він не може виглядати далі.

Ледачий припиниться, як тільки зустріне перший шаблон, про який ви просили.

Один поширений приклад, з яким я часто стикаюся, - це \s*-\s*? це регулярний вираз([0-9]{2}\s*-\s*?[0-9]{7})

Перший \s*класифікується як жадібний через те, що *після набору цифр буде виглядати якомога більше пробілів, а потім шукати штриховий символ "-". Де як другий \s*?лінивий через сьогодення, *?що означає, що він буде виглядати першим символом білого простору і зупиниться прямо там.


3

Найкраще показано на прикладі. Рядок. 192.168.1.1і жадібний вираз \b.+\b Ви можете подумати, що це дасть вам 1-й октет, але насправді відповідає цілому рядку. Чому? Оскільки. + Є жадібним, а жадна відповідність відповідає кожному символу, 192.168.1.1поки не досягне кінця рядка. Це важливий біт! Тепер він починає відслідковувати один символ за часом, поки не знайде збіг для 3-го маркера ( \b).

Якщо на початку був рядковий текстовий файл розміром 4 Гб і 192.168.1.1, ви могли легко зрозуміти, як ця зворотня перевірка спричинить проблему.

Щоб зробити регулярний вираз не жадібний (лінивий), після вашого жадібного пошуку поставте знак питання, наприклад

*?
??
+?

Що відбувається зараз - маркер 2 ( +?) знаходить відповідність, регулярний вираз рухається по символу, а потім намагається наступний жетон ( \b), а не маркер 2 ( +?). Так воно обережно повзає.


0

Жадібні квантори є як IRS / ATO: вони беруть стільки, скільки можуть:

Якщо він там, вони прийдуть і візьмуть його. Вони візьмуть усе:

Наприклад, IRS відповідає цій графіці: .*

$50,000 - IRS візьме все це. Цей жадібний .*{4}?ERS

Дивіться тут приклад: regexr.com/4t27f

Не жадібні квантори - вони беруть якомога менше

З іншого боку, якщо я попрошу повернення податку, раптом IRS стає не жадібним, і вони використовують цей кількісний показник:

(.{2}?)([0-9]*)проти цього виразу: $50,000Перша група не потребує і відповідає лише $5тому я отримую$5 відшкодування. Решту бере дядько Сем на марнотратні витрати.

Дивіться тут: Приклад, що не є жадібним .

Навіщо турбуватися?

Це стає важливим, якщо ви намагаєтеся відповідати певним частинам виразу. Іноді не хочеться відповідати всім.


-3

спробуйте зрозуміти таку поведінку:

    var input = "0014.2";

Regex r1 = new Regex("\\d+.{0,1}\\d+");
Regex r2 = new Regex("\\d*.{0,1}\\d*");

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // "0014.2"

input = " 0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // " 0014"

input = "  0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // ""
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.