PHP:preg_match()等で使う際の正規表現中の括弧の扱い

最終更新日時:2017-02-24 17:57:33
PHP

PHP で preg_match() を使った時に、括弧は特別な意味を持ちます。
具体的には、グループ化と後方参照が出来ます。
これにより、非常に紛らわしいことになる、、、といった問題がおきます。

後方参照


PHP の preg_match() 等には、後方参照という機能があります。
つまらない例ですが、以下のような例です。

 preg_match('/d(ef)/', "abcdef", $matches);


$matches に入る結果は、こうなります。

 Array
 (
     [0] => def
     [1] => ef
 )


これは、$matches[0] がマッチした文字列の全体、$matches[1] が括弧を指定したことによる後方参照の値が入るためです。


グループ化


一方、PHP では正規表現中で括弧を使うことによりグループ化することが出来ます。

 preg_match('/e|zf/', 'abcdefg', $matches);
 preg_match('/(e|z)f/', 'abcdefg', $matches);


上記は括弧を除けば同じ指定ですが、結果は異なります。

 Array
 (
     [0] => e
 )
 Array
 (
     [0] => ef
     [1] => e
 )



マッチした全体が入る $matches[0] の結果が異なっています。
これはつまり、マッチした部分が異なっていることを意味しています。
前者は "e" だけ、括弧でグループ化した後者は "ef" がマッチしています。

しかし、ここで注目すべきは、後者はグループ化のために括弧を使ったにもかかわらず、$matches[1] にも値が入っているところです。
これは、グループ化のために括弧を指定したにもかかわらず、後方参照としても括弧が使われてしまっていることを意味しています。

グループ化のみの指定


上記の現象が起きると困るケースがあります。
それは、グループ化と後方参照を混在した正規表現を指定するケースです。
この場合、通常は後方参照の順番が重要になるのですが、その中には意図していない(グループ化として指定した括弧による)後方参照が含まれてしまいます。
PHP の機能としてそういったものだと理解して使えば良いという話もあるのですが、なかなか気持ち悪い話です。

これを解決するため、PHP では、グループ化に特化した括弧の指定方法があります。
以下のように "(?:" で指定すると、後方参照されないグループ化指定となります。

 preg_match('/(?:e|z)f/', "abcdef", $matches);


結果は以下のようになります。

 Array
 (
     [0] => ef
 )


従って、PHP では、可読性的には微妙ですが、グループ化の際には明示的に "(?:" で指定するようにした方が間違いがないかと思います。

お問い合わせは 掲示板 にて。