【最短マッチ】正規表現で手前の文字列のみ取得したい場合は特性変更できる「?」を使う

正規表現最短マッチ

正規表現を覚えたてのときぶち当たる壁があります。取得したい場所を指定してしているのに要らないところまで取得してしまう。例ではhtmlのclass名のみ取得したいときぶち当たります。

<div class="test"><div class="test__in">test</div></div>

class「test」のみ取得したいとき

/class=\"(.*)\"/

PHPでは

<?php
 $source = '<div class="test"><div class="test__in">test</div></div>';
 $pattern = '/class=\"(.*)\"/';
 
 preg_match($pattern,$source, $m);

?>

こんな感じで書いたとします。しかし結果は

になってしまいます。よく考えると確かにそうなります。
しかし解決方法がなかなか見当たらないのです。ググりたいけどどういう状況かを説明できないので、はじめの場合は苦戦します。実はこの状況「最短マッチ」といいます。私は「正規表現 手前のみ取得」でたどり着きました。

.*?

「最短マッチ」させるためには一般的には以下のように書きます。

/class=\"(.*?)\"/

PHPでは

<?php
 $source = '<div class="test"><div class="test__in">test</div></div>';
 $pattern = '/class=\"(.*?)\"/';
 
 preg_match($pattern,$source, $m);

?>

?(はてな)を加えるだけでなぜか取得できます。

なぜ.*?で取得できるのか

*(アスタリスク)や?(はてな)は量指定子文字といい、前の文字を何回でてくるか指定することができる文字です。

量指定子 説明
* 0回以上の繰り返しにマッチ
? 0回または1回の出現にマッチする表現
+ 1回以上の繰り返しにマッチ
{n} n回の繰り返しにマッチする表現
{n,} n回以上の繰り返しにマッチする表現
{n,m} n回以上m回以下の繰り返しにマッチする表現

量指定子はデフォルトで「できるだけ長い文字列にマッチさせる特性(最長一致)」をもっています。そのため「*(アスタリスク)」はできる長く取得するため初めに書いたように予定していないところまで取得したのです。この特性を変更させるのが「?(はてな)」です。量指定子の後ろに「?」をつけると特性が「できるだけ短い文字列にマッチする特性(最短一致)」に変わります。上記の量指定子だけ覚えていると意味がわかりませんが、「?」には特性を変更できる特殊な能力があると覚えておくと便利に利用できます。

特性変更
.* 最長一致

.*? 最短一致

連続して取得したいとき

以下のソースのクラスを全て取得したいときはどのようにすればいいでしょうか。

<div class="test"><div class="test__in">test</div></div>

「test」「test__in」も取得したい。

PHPの場合では連続マッチできる関数があります。
preg_match 単一

preg_match_all 連続

<?php
 $source = '<div class="test"><div class="test__in">test</div></div>';
 $pattern = '/class=\"(.*?)\"/';
 
 preg_match_all($pattern,$source, $matches, PREG_OFFSET_CAPTURE);

 foreach($matches[1] as $result){
     echo str_replace(" ","<br>",$result[0]) . "<br>";
 }
 
?>

シェアする

  • このエントリーをはてなブックマークに追加

フォローする