本文へスキップ
BecomeCoder

正規表現コース · 第3章 繰り返しを表す · レッスン9

欲張りと控えめ ― greedy と lazy

ブラウザで完結

導入

量指定子には「できるだけ多くマッチしようとする」性質があります。これを 欲張り(greedy) と呼びます。この性質を知らないと「思ったより広い範囲がマッチしてしまう」という、正規表現で最もよくあるつまずきに遭遇します。

説明

たとえば HTML のタグを <.*> で取り出そうとすると、意図とずれます。

パターン: <.*>
対象:     <b>太字</b>
マッチ:   [<b>太字</b>]  ← 最初の < から最後の > まで、丸ごとマッチしてしまう!

.* は「任意の文字を0個以上」ですが、できるだけ長く マッチしようとするため、途中の > を飛び越えて最後の > まで飲み込みます。

これを「できるだけ短く」に変えるのが、量指定子の後ろに付ける ? です。*? +? ?? {n,m}?控えめ(lazy/非貪欲) と呼びます。

パターン: <.*?>
対象:     <b>太字</b>
マッチ:   [<b>]太字[</b>]  ← 最短で止まるので、タグを1つずつ取り出せる

もうひとつの手は、そもそも欲張らせないこと。「> 以外を繰り返す」と書けば、> を飲み込みません。

パターン: <[^>]*>
対象:     <b>太字</b>
マッチ:   [<b>]太字[</b>]  ← 否定文字クラスで確実に1タグずつ

多くの場合、<[^>]*> のように 否定文字クラスで書くほうが速く・確実 です。lazy(*?)は便利ですが、まずは「.* は欲張る」という性質を頭に入れておくことが大切です。

やってみよう

.* は「最長」を狙う ―― この欲張りの性質を覚えましょう。短く止めたいときは .*?、あるいは [^X]*(Xを避ける)を使う、と引き出しを持っておくと安心です。

実際に動かしてみよう

パターン欄に正規表現を、下の「テスト文字列」欄に対象の文字列を入れると、マッチした部分がその場でハイライトされます(ブラウザ標準の正規表現エンジンで動きます)。フラグ(g/i/m/s)を切り替えたり、本文のパターンを書き換えたりして、マッチの変化を確かめながら進めましょう。

正規表現 — その場でマッチを確認

ブラウザ標準の正規表現エンジンでパターンを試せる学習用ウィジェットを読み込みます(外部エンジン不要・軽量です)。
スクロールして表示された時点でも自動で読み込まれます。