正規表現
ほぼあらゆるプログラミング言語では、正規表現を使って文字列のパターンをマッチングすることができますよね。今回正規表現のちょっとしたトラップにハマったのが悔しかったので調べて記事にしようと思います。結論から言えば、正規表現には、"lazy(怠惰)"と"greedy(貪欲)"の2つの種類があります。この記事では、これら2つの種類の違いについて見ていきます。
Lazy(怠惰)な正規表現
Lazyな正規表現では、文字列の最短マッチングを行います。つまり、マッチする部分文字列が見つかった場合、即座にその部分文字列を結果として確定させ、それ以降の文字列に対してマッチングを続けます。
例えば、次のコードを見てみましょう。
const lazyRegex = /a(.*?)b/g;
const input = "abaaxyzbadb";
const result = input.match(lazyRegex);
console.log(result); // ["ab","aaxyzb", "adb"]
このコードは、"aaxyzbadb"という文字列から"a"と"b"に挟まれたの最短("ab"を含む)の文字列をマッチングしようとします。Lazyな正規表現では、".*?"を使って最短のマッチングを行い、["ab","aaxyzb", "adb"]という3つの文字列をマッチングします。
Greedy(貪欲)な正規表現
Greedyな正規表現は、文字列の最長マッチングを行います。つまり、パターンにマッチする部分文字列の中で最も長いものを返してきます。
例えば、次のコードを考えてみましょう。 lazyRegex
から?
が消えているのがポイントです。
const lazyRegex = /a(.*)b/g;
const input = "abaaxyzbadb";
const result = input.match(lazyRegex);
console.log(result); // ["abaaxyzbadb"]
上記のコードは、"abaaxyzbadb"という文字列から"a"と"b"に挟まれた最長の文字列をマッチングしようとしています。Greedyな正規表現は、".*"を使って最長のマッチングを行い、"abaaxyzbadb"という文字列全体をマッチングします。
まとめ
今回は正規表現における"lazy"と"greedy"の違いについて説明しました。Lazyな正規表現は、最短のマッチングを行い、Greedyな正規表現は最長のマッチングを行います。言語によって記法は多少違うと思いますが、私のように知らないと見落とすので普段使っている言語の正規表現を改めて調べてみても良いかもしれません。