【PHP】 正規表現のエスケープ
phpで正規表現(preg系)のエスケープシーケンスの書き方について調べた。
以下のような正規表現がある。
$text = 'abc/def'; preg_match('/abc\\/def/', $text); # (a) preg_match('/abc\/def/', $text); # (b)
さて(a)と(b)、どっちが正しいか?
答えはどっちでもOK。
とはいえ(1)はうまく評価されるが、間違った書き方だと思う。
PHPのマニュアルに、
シングルクォートあるいはダブルクォートで囲まれた 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マニュアルにも書いてないので、イレギュラーな方法と思っておく。
【参考】