スクリプトガイド > データタイプ > 正規表現 > 貪欲な正規表現と控えめな正規表現
公開日: 04/01/2021

貪欲な正規表現と控えめな正規表現

?*+の各演算子はデフォルトで貪欲なマッチを行う正規表現です。前にあるできるだけ多くの文字にマッチします。?演算子は、それらを控えめにします。??は0をマッチし、必要に応じて1にマッチします。+?1にマッチし、さらに他の文字にマッチします。*?0にマッチし、さらに他の文字にマッチします。

次の例は、文字nで始まり、それをパターン内の最初の\d(数字)と比較します。数字ではないのでマッチしません。パターンが^(行の最初)で始まっていないため、マッチはuに進みます。3が最初の\dにマッチし、2が2番目の\dにマッチするまで、このプロセスが繰り返されます。

Regex( "number=32.5", "\d\d" );

"32"

パターンを貪欲にするには、+(1つ以上にマッチ)を使います。

Regex( "number=324.5", "\d+" );

"324"

前述の例は、最初はだいたい同じですが、3が見つかり、\dがマッチすると、+24にも貪欲にマッチします。

通常、貪欲なパターンマッチを行うと、文字列が早く消費されるため、マッチが高速になります。場合によっては、控えめなマッチの方が良いこともあります。?*または+の後ろに追加すると、貪欲から控えめに変わります。

Regex( "number=324.5", "\d+?" );

"3"

ここで、+は少なくとも1つの数字のマッチを必要としますが、?によって「できるだけ多く」が「できるだけ少なく」に変わります。3の後で、パターンが満たされたため停止します。

次の結果を比較します。

貪欲:

Regex( "number=324.5", "(\d+)(\d+)\.", "first=\1 second=\2" );

"first=32 second=4"

控えめ:

Regex( "number=324.5", "(\d+?)(\d+?)\.", "first=\1 second=\2" );

"first=3 second=24"

上記の貪欲な例では、最初の\d+に対して324が貪欲にマッチされます。その後、2つ目の\d+がマッチできるように、4が戻されます。控えめな例では、別の経路を使い、異なる答えにたどり着きます。最初、2番目の値は2でしたが、パターンがピリオドを4にマッチできなかったため、2つ目の\d+?が控えめに4にもマッチしました。

控えめなマッチで高速化

貪欲なマッチと控えめなマッチは、同じ結果を出すことが多いですが、そうでない場合もあります。前の節を参照してください。控えめなマッチを使用する理由の一つに、速度が挙げられます。「The quick fox…」で始まる100万字の文字列があり、「fox」の直前の語を知りたいとします。\1に「quick」が含まれると予想して、次のような式を書くかもしれません。

The (.+) fox

\1に「quick」が含まれる可能性はあります。.+が文字列の最後まで、計100万個の文字を捉え、「fox」が見つかるまで1語ずつ手放します。「fox」が2個以上ある場合は、最初ではなく最後の「fox」が見つかります。速く、確実に最初の「fox」が見つかるようにするには、?演算子を追加します。

The (.+?) fox

?は、1文字ずつ前進し、「quick」を通過して最初の「fox」を見つけます。この方法なら、遠くへ進み過ぎるよりずっと速く処理できます。

通常、+または*の演算子は、\d*のような限定的な表現に適用され、一連の数字をマッチします。貪欲なマッチの方が控えめなマッチより高速です。

「fox」が複数ある可能性を別にすれば、貪欲なマッチと控えめなマッチでは最終的に同じ答えが出ます。適切な演算子を使えば、マッチの速度が上がります。貪欲が適しているときもあれば、控えめな方がよい場合もあります。それは、マッチする対象によって異なります。

貪欲な.*は、まず最後まで移動した後、最後の「fox」を見つけます。

Regex(
	"The quick fox saw another fox eating grapes",
	"The (.*) fox",
	"\1"
);

"quick fox saw another"

控えめな.*?は最初の「fox」で停止します。

Regex(
	"The quick fox saw another fox eating grapes",
	"The (.*?) fox",
	"\1"
);

"quick"

貪欲な.*は、処理を何度も繰り返さなければなりません。2つ目の「fox」はありません。

Regex(
	"The quick fox saw another animal eating grapes",
	"The (.*) fox",
	"\1"
);

"quick"

次の例では、貪欲な文字マッチの方が適しています。

Regex(
	"The quick fox saw another fox eating grapes",
	"The (\w*) fox",
	"\1"
);

"quick"

より詳細な情報が必要な場合や、質問があるときは、JMPユーザーコミュニティで答えを見つけましょう (community.jmp.com).