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


回答:


644

貪欲は可能な限り消費します。http://www.regular-expressions.info/repeat.htmlから、HTMLタグをと照合する例を確認できます<.+>。次のものがあるとします。

<em>Hello World</em>

あなたはと思うかもしれ<.+>.手段以外の改行文字+手段1つまたは複数の)のみ一致し<em>そして</em>実際に、それは非常に貪欲になり、最初から行くと、<最後に>。これは、<em>Hello World</em>あなたが望んだものの代わりに一致することを意味します。

レイジー(<.+?>)にすると、これを防ぐことができます。追加することで?後に+、我々は繰り返すということを教えできるだけ何回かのように最初ので、>に出くわす部分で、マッチングを停止します。

正規表現の探索に役立つ優れたツールであるRegExrをダウンロードすることをお勧めします。私は常に使用しています。


2
あなたが貪欲を使用する場合、あなたは3つ(1要素+ 2タグ)の一致を持っていますか、それともただ1つの一致(1要素)を持っていますか?
ajsie 2010

10
最初の<から始まり、最後の>で終わる1回だけ一致します。
サンプソン

3
ただし、遅延させると2回一致し、開始タグと終了タグの両方が与えられ、その間のテキストは無視されます(式に適合しないため)。
サンプソン

私がいつも使用しているもう1つの優れたツール:debuggex.com「Embed on StackOverflow」機能もあります。
Ron van der Heijden、2014年

8
それに加えて、貪欲な方法もあります:<[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan

302

'Greedy'は、可能な限り長い文字列に一致することを意味します。

「レイジー」は、可能な限り短い文字列に一致することを意味します。

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


97
華麗なので、怠惰は条件lが満たされるとすぐに停止しますが、貪欲は条件lがもう満たされない場合にのみ停止することを意味しますか?
アンドリューS 14

3
投稿を読んでいるすべての人にとって:貪欲または遅延の数量詞だけでは、可能な限り最長/最短の部分文字列は一致しません。強化された貪欲なトークンを使用するか、非正規表現アプローチを使用する必要があります。
WiktorStribiżew2016年

3
@AndrewS例の二重llと混同しないでください。貪欲は可能な限り最長の文字列に一致するのに対し、それはむしろ怠惰です。貪欲はh.+l一致'helol'します'helolo'が、遅延がh.+?l一致し'hel'ます。
v.shashenko 2017年

3
@FloatingRock:いいえ。x?意味xはオプションですが+?、構文が異なります。それはあなたが一致するものを見つけた後、見るのをやめることを意味します-遅延一致。
slebetman 2017

1
@FloatingRock:異なる構文をどのように区別するかについては、単純:?はオプションを+?意味し、遅延を意味します。したがって、\+?手段+はオプションです。
slebetman 2017

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
greedy reg式s.*o出力:stackoverflo w
レイジーreg式s.*?o出力:stacko verflow


2
ではありません ??に相当 ?。同様に、{n}ではありませんか?{n}と同等
Number945

5
@BreakingBenjamin:いいえ?? ?と同等ではなく、0または1のいずれかを返す選択がある場合、0(遅延)の代替を選択します。違いを確認するには、と比較re.match('(f)?(.*)', 'food').groups()してくださいre.match('(f)??(.*)', 'food').groups()。後者で(f)??は、可能であっても先頭の「f」に一致しません。したがって、「f」は2番目の「。*」キャプチャグループに一致します。'{n}?'で例を構築できると思います。あまりにも。確かに、これら2つはほとんど使用されていません。
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>']

最初に出現する「>」まで一致する代わりに、文字列全体を抽出しました。これは、正規表現のデフォルトの貪欲または「すべてを実行」する動作です。

一方、レイジーマッチングは、「最小限の時間しかかかりません」。これ?は、パターンの最後にa を追加することで実行できます。

例:

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

最初に一致したものだけを取得したい場合は、代わりにsearchメソッドを使用してください。

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

ソース:Python正規表現の例


3

貪欲とは、パターンがなくなるまでパターンを消費し、それ以上見えなくなることを意味します。

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

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

1つ目\s**、数字が検出された後に可能な限り多くの空白を探し、次にダッシュ文字「-」を探すため、貪欲として分類されます。2番目\s*?は現在のために遅延であるので*?、1番目の空白文字が表示され、そこで停止します。


3

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

文字列が4GBのテキストファイルで、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); // ""
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.