PHP
正規表現
バックスラッシュ

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でバックスラッシュをマッチング
・エスケープシーケンス
・私の正規表現におけるポリシー
・正規表現のエスケープ