web-dev-qa-db-ja.com

正規表現の文脈で「怠惰」と「欲張り」はどういう意味ですか?

誰かがこれら2つの用語をわかりやすい方法で説明できますか?

429
ajsie

貪欲はできるだけ多くを消費します。 http://www.regular-expressions.info/repeat.html から、HTMLタグを<.+>と一致させようとする例が見られます。次のものがあるとします。

<em>Hello World</em>

<.+>.は改行以外の文字を意味し、+は1つ以上を意味)は<em></em>、実際には非常に貪欲になり、最初の<から最後の>まで進みます。これは、あなたが望むものではなく<em>Hello World</em>にマッチするということです。

それを怠惰(<.+?>)にするとこれを防ぐことができます。 ?の後に+を追加することで、可能な限り少ない回数で繰り返すように指示します。そのため、最初の>がマッチングを停止したいところです。

RegExr をダウンロードすることをお勧めします。これは、正規表現を探索するのに役立つでしょう - 私はいつも使っています。

545
Sampson

'欲張り'は、最長の文字列と一致することを意味します。

'Lazy'は、一致する最短の文字列を意味します。

たとえば、貪欲なh.+l'hell'内の'hello'と一致しますが、遅延h.+?l'hel'と一致します。

259
slebetman
+-------------------+-----------------+------------------------------+
| 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
欲張りreg式s.*o 出力:stackoverflow
lazy reg式s.*?o 出力:stacko動詞

85
Premraj

貪欲はあなたの表現が可能な限り大きいグループにマッチすることを意味し、lazyは可能な限り小さいグループにマッチすることを意味します。この文字列の場合:

abcdefghijklmc

そしてこの式は:

a.*c

貪欲な一致は文字列全体に一致し、遅延一致は最初のabcにのみ一致します。

49
Carl Norum

私の知る限りでは、ほとんどの正規表現エンジンはデフォルトで欲張りです。数量詞の最後に疑問符を追加すると、遅延一致が有効になります。

@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");
        }
    }
}

私は貪欲です、そして私は100000000ドルが欲しいです。これが私が得ることができる最も多いものです。

私はそんなにお金を稼ぐのが面倒だ、たった100ドルで十分だ

12
Gearon

撮影元: www.regular-expressions.info

貪欲:貪欲数量詞はまずトークンを可能な限り繰り返すことを試み、全体の一致を見つけるためにエンジンがバックトラックするにつれて徐々に一致を放棄します。

Laziness:Lazyinessは最初にトークンを必要な回数だけ繰り返し、全体の一致を見つけるためにエンジンが正規表現をたどっていくにつれて徐々に一致を拡大します。

From 正規表現

正規表現の標準的な量指定子は欲張りです。つまり、可能な限りマッチし、残りの正規表現にマッチするのに必要なだけ返されます。

遅延数量詞を使用することによって、式は最初に最小一致を試みます。

6
Adriaan Stander

貪欲は、それらがどれも残らなくなるまでそれがあなたのパターンを消費することを意味し、それはそれ以上見られなくなります。

あなたが要求した最初のパターンに遭遇するとすぐに、Lazyは停止します。

私がよく遭遇する一般的な例の1つは、正規表現の\s*-\s*?です([0-9]{2}\s*-\s*?[0-9]{7})

最初の\s*は、*のために欲張りとして分類され、数字に出会った後できるだけ多くの空白を見てからダッシュ文字 " - "を探します。 2番目の\s*?は、*?の存在のために怠惰です。これは、最初の空白文字を見てそこで止まることを意味します。

3
stackFan

例で最もよく示されています。文字列192.168.1.1と貪欲な正規表現\ b。+\bあなたはこれが最初のオクテットを与えると思うかもしれませんが、実際には文字列全体に対してマッチします。なぜ!!!なぜなら。+は欲張りで、欲張りな一致は文字列の最後に達するまで '192.168.1.1'内のすべての文字にマッチするからです。これは重要なことです!これで、3番目のトークン(\ b)に一致するものが見つかるまで、一度に1文字ずつバックトラックを開始します。

4GBのテキストファイルと192.168.1.1の文字列が最初の部分にある場合は、このバックトラックがどのように問題を引き起こすのかを容易に確認できます。

正規表現を非欲張り(怠惰)にするには、欲張り検索の後に疑問符を付けます。 ? +?トークン2(+?)が一致を見つけ、正規表現が文字に沿って移動し、トークン2(+?)ではなく次のトークン(\ b)を試すようになりました。それで、それはしょうがに沿って忍び寄ります。

2
Jason Alcock

欲張りなマッチング正規表現のデフォルトの振る舞いは欲張りです。つまり、より小さな部分で構文的に十分であったとしても、パターンに一致するまで可能な限り抽出しようとします。

例:

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正規表現の例

2
Selva

誰かが解析時により高速なものを探してここに来た場合:

正規表現のパフォーマンスに関する一般的な誤解は、怠laな量指定子(貪欲でない、消極的、最小、または貪欲でないとも呼ばれます)は貪欲な同等物よりも速いということです。これは一般的には正しくありませんが、重要な修飾子があります。実際には、遅延量指定子の方が高速です。

Flagrant Badassery からの抜粋

1
User_coder