開発ブログ

WWWクリエイターズが送る、Git、CSS、HTML、コマンドライン、Macの便利機能など、開発に関する役立ち情報発信します。気まぐれに更新。

正規表現:最短一致でマッチさせる表現

最終更新:2017-07-29 by Joe

正規表現を使って「最短一致」でマッチングを取ります。

通常、正規表現では、「*」などの量指定子を利用してマッチを検出した時、「最長一致」を検出しますが、特定の記述方法によって、パターンの「最短一致」を表現することができます。

最短一致でマッチさせる

正規表現での「*」「+」「?」「{n}」などの量指定子(quantifier)は、入力中に文字、グループ、または文字クラスやメタ文字などの後ろにくっつけることで、「文字の繰り返し」を表現できるのはよく知られています。

このとき量指定子は、デフォルトでは「Greedy(欲張り)なマッチ」を行う仕様となっており、可能な限り長い文字列のマッチを探してしまいます。

そのような量指定子の直後に「?」を置くことで、逆に「Non-greedy(最短)なマッチ」を表現でき、可能な限り短い文字列のマッチを検出できます。

正規表現の両指定子

最長一致
(greedy)
最短一致
(Non-greedy)
表現
* *? 0個以上
? ?? 0〜1個
+ +? 1個以上
{n} {n}? n個
{n,} {n,}? n個以上
{,m} {,m}? m個以下
{n,m} {n,m}? n個以上、m個以下

例えば、

から<a></a>で囲まれたアンカータグを「1つだけ」取り出す事を考えます。

改行以外のすべての文字を表す「.」を利用して、「<a.*</a>」と言った正規表現が思いつきます。

ですが、これだと「最長一致」を探してしまい、その文字列すべて(2つのアンカータグをひと続きで)をマッチしてしまいます。

ここで、上記のNon-greedyなマッチングを利用します。

「?」記号を利用した最短一致でマッチさせれば、個々のアンカー要素を取り出すことができそうです。

実際の正規表現の例

下記に例を見てみます。

Javascript

RegExpクラスの「testメソッド(booleanを返す)」「execメソッド(nullか、もしくはマッチ文字列の配列を返す)」を使えます。

なお、Javasciptでは、正規表現リテラルを使って、「var re = /<a.*?<\/a>/;」とも表現できますが、上記のようにnewを利用するとデリミタを書く必要がないので、スラッシュをエスケープしなくて済みます。(Javascriptでは、デリミタに「/」以外が使えないのです)お好みでどうぞ。

PHP

preg_xxx系の関数は色々あります。(PHPマニュアル:preg_match)下記は最も基本的な、マッチング結果をbooleanで返す関数の例です。

引数の使い方に注意します。3番目の変数に、後方参照用の配列を渡します。見つかれば、その配列の、N番目の要素に、マッチのN番目が入ります。

また、通常は、デリミタを「/ (スラッシュ)」で記述しますが、代わりに「#」を利用することで、スラッシュをエスケープする必要がなくなります。これは便利ですよね。デリミタは英文字やバックスラッシュ、スペース以外ならなんでもいいようです。

筆者は「#」をよく使います。(お好みでどうぞ。)

Vim

 

ちなみに、末尾に「n」をつけることで、文字列置換を実際には行いません。マッチのカウントをVIM上に表示だけするためにこれ付けています。

正規表現に関する参考リンク

さて、うまく最短一致の正規表現がかけたでしょうか?

現場からは以上です。