takafumi blog

日々の勉強メモ

【PHP】 正規表現のエスケープ

環境   CentOS 7.0  PHP 7.0.1

php正規表現(preg系)のエスケープシーケンスの書き方について調べた。


以下のような正規表現がある。

$text = 'abc/def';

preg_match('/abc\\/def/', $text); # (a)
preg_match('/abc\/def/', $text);  # (b)

さて(a)と(b)、どっちが正しいか?

答えはどっちでもOK。

とはいえ(1)はうまく評価されるが、間違った書き方だと思う。

PHPのマニュアルに、

PHP: エスケープシーケンス - Manual
注意:

シングルクォートあるいはダブルクォートで囲まれた PHP の 文字列 の中では、バックスラッシュは特別な意味を表します。 そのため、正規表現 \ を使用して \ とマッチさせたい場合は PHP のコード内では "\\" あるいは '\\' と記述する必要があります。

とある。 つまり

1.PHPの文字列として評価

2.正規表現エンジンでパターンを評価

とされるからバックスラッシュ自体を評価するときは、重ねましょうと言う話のはず。


(a)のように書く人は、以下のように判断していると思われる。

1.PHPの文字列として評価

/abc\\/def/ => /abc\/def/

2.正規表現エンジンでパターンを評価

abc\/def => abc/def

確かに正しく動く。
だが、そもそも正規表現エンジン内では、/(スラッシュ)はエスケープの必要はない。

なので、なので本来は(b)のパターンでOKで問題ない。


ではバックスラッシュは?

もとのPHPが以下だとする。

$text = '\\';
preg_match('/\\/', $text);   # (c)
preg_match('/\\\/', $text);  # (d)
preg_match('/\\\\/', $text); # (e)

これだと(c)はエラーに、(d),(e)はマッチする。

(c)がエラーになるのは

1.で評価された結果、/\/となる。

しかし2.で評価されるときに、\しか渡ってこない。
そのため正規表現エンジンに正常に評価されず、エラーになる。


(e)は
1.で/\\/と変換され、2.で正規表現エンジンんい\\が渡される。 なので正常に評価される。


では(d)は?
実はこれが良くわからない。
PHPの評価順のせいか正常に評価される。
が、普通に考えれば、1.の段階で3つ目の\がスラッシュにかかりそうなもの。 しかし、正常に評価される。PHPの評価順のせいなのか?

とはいえPHPマニュアルにも書いてないので、イレギュラーな方法と思っておく。


【参考】

qiita.com