정규 표현식의 맥락에서 '게으른'과 '욕심쟁이'는 무엇을 의미합니까?


답변:


644

탐욕은 가능한 한 많이 소비 할 것입니다. 에서 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 회만 일치합니다 .
Sampson

3
그러나 게으르게 만드는 것은 두 번 일치하여 여는 태그와 닫는 태그를 제공하고 사이에 텍스트를 무시합니다 (표현식에 맞지 않기 때문에).
Sampson

내가 항상 사용하는 또 다른 훌륭한 도구 : debuggex.com "Embed on StackOverflow"기능도 있습니다.
Ron van der Heijden

8
욕심 많은 방법도 있다는 것을 <[^>]+> 덧붙여서
alanbuchanan

302

'Greedy' 는 가능한 가장 긴 문자열과 일치 함을 의미합니다.

'게으른' 은 가능한 가장 짧은 문자열과 일치 함을 의미합니다.

예를 들어, 욕심 h.+l경기 'hell'에서 'hello'하지만 게으른 h.+?l경기 'hel'.


97
훌륭하다. 그래서 조건 l이 충족 되 자마자 게으른 것이 멈추지 만, 욕심은 조건 l이 더 이상 충족되지 않으면 멈추는 것을 의미합니까?
Andrew S

3
글을 읽는 모든 사람들에게 : 탐욕 스럽거나 게으른 수량자는 그 자체로 가장 긴 / 가장 짧은 부분 문자열과 일치하지 않습니다. 강화 욕심쟁이 토큰 을 사용하거나 정규식이 아닌 방법을 사용해야합니다.
Wiktor Stribiżew

3
@AndrewS 예제에서 이중 ll로 혼동하지 마십시오. 다소 게으른 것은 가능한 가장 짧은 부분 문자열과 일치하지만 욕심은 가능한 가장 긴 부분 문자열과 일치합니다. 욕심 h.+l경기 'helol'에서 'helolo'하지만 게으른 h.+?l경기 'hel'.
v.shashenko

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  |
+-------------------+-----------------+------------------------------+

추가하다 ? 수량 자에게 불명예스러운 게으른.

예 :
테스트 문자열 : 유래
욕심 레그 식 : s.*o출력 : stackoverflo w
지연 레그 식 : s.*?o출력 : stacko verflow


2
아니다 ?? ?에 해당 . 마찬가지로 {n}이 아닙니까?
Number945 년

5
@BreakingBenjamin : 아니오 ?? 0 또는 1을 반환하도록 선택할 수있는 경우?와 동등하지 않으며 0 (lazy) 대안을 선택합니다. 차이를 확인하려면 비교 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 에서 가져옴

Greediness : Greedy 한정자는 먼저 토큰을 가능한 한 여러 번 반복하려고 시도하고 전반적인 일치를 찾기 위해 엔진 역 추적에 따라 점차적으로 일치를 포기합니다.

게으름 : 게으른 수량자는 먼저 필요한만큼 토큰을 반복하고 엔진이 정규식을 통해 역 추적 할 때 전체 일치를 찾기 위해 점차적으로 일치를 확장합니다.


6

에서 정규 표현식

정규 표현식의 표준 수량자는 욕심이 많으므로 가능한 한 많이 일치하므로 나머지 정규 표현식과 일치하는 데 필요한만큼만 제공합니다.

게으른 수량자를 사용하면식이 최소 일치를 먼저 시도합니다.


4

욕심 매칭. 정규 표현식의 기본 동작은 욕심입니다. 즉, 작은 부분이 구문 적으로 충분했을 때에도 패턴에 맞을 때까지 가능한 한 많이 추출하려고 시도합니다.

예:

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

'>'가 처음 나타날 때까지 일치하는 대신 전체 문자열을 추출했습니다. 이것은 정규 욕심 또는 정규식의 '모두 가져 가기'행동입니다.

반면에 게으른 일치 는 '가능한 한 적게 가져갑니다'. 이것은 ?패턴의 끝에 a 를 추가하여 수행 할 수 있습니다 .

예:

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

첫 번째 일치 항목 만 검색하려면 검색 방법을 대신 사용하십시오.

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

출처 : 파이썬 정규식 예제


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는 문자열 끝에 도달 할 때까지 모든 문자와 일치 합니다. 이것은 중요한 비트입니다! 이제 세 번째 토큰 ( \b) 과 일치 할 때까지 한 번에 한 문자 씩 역 추적하기 시작합니다 .

문자열에 4GB 텍스트 파일과 192.168.1.1이 시작되면이 역 추적이 어떻게 문제를 일으키는 지 쉽게 알 수 있습니다.

정규식을 욕심없는 (게으른) 만들려면 탐욕스러운 검색 뒤에 물음표를 넣으십시오.

*?
??
+?

이제 토큰 2 ( +?)가 일치하는 것을 찾고 정규식이 문자를 따라 이동 한 다음 \b토큰 2 ( +?) 대신 다음 토큰 ( ) 을 시도합니다 . 그래서 그것은 진지하게 섬뜩합니다.


0

Greedy Quantifier는 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); // ""
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.