Perlにおいて、正規表現の量指定子 *, +, ?, {n,m} はデフォルトで貪欲(greedy)です:彼らは、パターンに一致する可能な限り多くの文字をキャプチャします。
量指定子の後に ? を追加すると、それは遅延(lazyまたはnon-greedy)になり、一致する正規表現全体が合うために最小限の文字をキャプチャします。
my $str = 'foo <bar> baz <quux>'; $str =~ /<.*>/; # '<bar> baz <quux>'をキャプチャします
my $str = 'foo <bar> baz <quux>'; $str =~ /<.*?>/; # '<bar>'をキャプチャします
貪欲な表現は、HTMLや他の入れ子構造の解析時に予期しないほど多くを「食べる」ことがあります!
<a><b><c>という文字列の解析において、次の二つの正規表現/<(.*)>/と/<(.*?)>/は何が違いますか?
回答:
/<(.*)>/ (貪欲)は最大のブロックをキャプチャします — 一致:<a><b><c>/<(.*?)>/ (遅延)は最初のグループだけをキャプチャします:<a>例:
my $s = '<a><b><c>'; $s =~ /<(.*)>/; # $1: 'a><b><c' $s =~ /<(.*?)>/; # $1: 'a'
物語
ニュース見出しをインポートするアプリケーションで、プログラマーは
/\<(.*)\>/を使用して<title>ニュース</title>のタグ名を解析しようとしました。その結果、正規表現は最初の<と最後の>の間の全ての文字列をキャプチャしましたが、必要な要素をキャプチャしませんでした。入れ子のタグが現れたときにエラーが見つかりました。
物語
論理パーサーにおいて、quoted stringsを抽出するために使用されたパターン
/"(.*)"/は予期せず最初と最後の引用符の間の全てをキャプチャしました。その結果、マークアップが正しく分解されず、パターンを/"(.*?)"/に置き換えるまで問題が解決しませんでした。
物語
引用符を含むCSVの自動パーサーでは、「貪欲」に基づいたパターンが誤って書かれたため、複数の列が一つに結合されてしまいました。入力されたパーサーの拒否は大規模データでのみ明らかになり、パターンの遅延修正が問題を解決しました。