Posted at

preg_matchでバックスラッシュをマッチさせる方法

バリデーションで大活躍のpreg_match。

preg_matchで\の正規表現で書いてみると、コンパイルエラーで怒られる。

$value = "¥¥";

if (preg_match("/^[\\]+$/", $value)) {
echo "OK";
} else {
echo "NG";
}

// 実行結果
PHP Warning: preg_match(): Compilation failed: missing terminating ] for character class at offset 6 in

とりあえずメタ文字・特殊文字はエスケープすれば良いだろうと安易に考えてましたが、そうでもないらしい。

悩みつつも適当に\をいじっていると急に正常動作しました。

$value = "¥¥";

if (preg_match("/^[\\\]+$/", $value)) {
echo "OK";
} else {
echo "NG";
}
// 実行結果 OK

さすがにコレで一件落着は気持ち悪いので、理由を色々しらべてみると、公式ドキュメントに辿り着く。

公式ドキュメントでは以下のように書かれています。


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


\を4つ並べるのが正しいようです。

$value = "\\";

if (preg_match("/^[\\\\]+$/", $value)) {
echo "OK";
} else {
echo "NG";
}
// 実行結果 OK

確かに正常に動作しましたが、"\\\"でも'\\\'でも動作します。

それから色々調べてみると、有識者の方々がエスケープ処理は二段構え(PHP言語レベルでのエスケープと正規表現エンジンレベルでのエスケープ)であることを言われていました。

preg_match('/\\/', $value);   // ①

preg_match('/\\\/', $value); // ②
preg_match('/\\\\/', $value); // ③

①の場合、まずPHPで評価されて「\」のみが返さるので、preg_matchで正しく評価できずにエラー。

③は「\\」が返ってきて正しく評価できます。

ちなみに②はよく分からないそうです。

あと3つは大丈夫でも5つダメでした。

何やら闇が深そうなのでまた今度mm


参考

・正規表現でエスケープが必要な文字一覧表

・preg_matchでバックスラッシュをマッチング

・エスケープシーケンス

・私の正規表現におけるポリシー

・正規表現のエスケープ