preg_quoteで特殊文字をエスケープ
preg系関数は非常に便利で、perl互換の正規表現が使えます。 ユーザーの入力内容のバリデートや文章の整形など、使いかたは様々です。
便利なpreg系関数ですが、検索するパターンに正規表現で用いる特殊文字を使いたい場合は「\」(バックスラッシュまたは円記号)を付けてエスケープする必要があります。
ですが、「ユーザーからの入力値をパターンにしたい時」のように動的に値が変わる場合は、手動でエスケープすることはできませんし、「プログラムの構文を整形したい時」「ファイル名の置換をしたい時」などの場合は、エスケープする文字が多くなりソースコードが読みにくくなってしまいます。
もちろん、ループ文でエスケープする処理を書くこともできますが、preg系関数には特殊文字をエスケープする関数「preg_quote」があるので簡単にエスケープできます。
preg_quoteがエスケープする文字は、
. \ + * ? [ ^ ] $ ( ) { } = ! < > | :
です。preg系関数で用いる特殊文字は一通りエスケープすることができるのですが、"/"はエスケープしてくれません。(これのエスケープ方法は後述します)
例えば、「George is man?」を「George is man.」に置換したいという場合を考えてみます。
検索パターン($pat)には「man?」を指定して、置換する文字列($rpl)には「man.」を指定しています。
$txt = "George is man?";
$pat = "/man?/";
$rpl = "man.";
$str = preg_replace($pat, $rpl, $txt);
この場合、予想通りに動作するようにも見えますが、preg_replaceの第一引数は 「/man?/」なので、「ma」、「man」にマッチしてしまい、結果は「man.?」になってしまいます。
予想通りに動作させるには、検索パターンの「man?」を「man\?」にする必要があります。この処理を自動的にやってくれるのが、preg_quoteです。
$txt = "George is man?";
$pat = "/man?/";
$rpl = "man.";
$str = preg_replace(preg_quote($pat), $rpl, $txt); //preg_quoteを使用
のようにすれば、「?」をエスケープして「man\?」となり、「man?」にマッチするので無事に「Gorge is man.」に置換できます。
便利なpreg_quoteですが、上記の例ではデリミタである"/"は自動的にはエスケープしないので"http://www"のようなものには使えません。このような場合は、preg_replaceの第二引数を使用します。
第二引数にはデリミタとして使用するエスケープしたい任意の文字列を指定できるので、ここで"/"を指定すれば、
$txt = "http://example.com/main/pictures/";
$pat = "http://example.com/";
$rpl = "/var/www/";
$str = preg_replace("/" . preg_quote($pat, "/") . "/", $rpl, $txt);
のようなコードでも正常に動作させることができます。
このpreg_quoteは、プログラムを予想通りに動作させること以外に、
//preg_quote非使用
$pat =
"//\.\.\/hoge\/piyo-fuga\/\[07-02-02\]\(subtitle\)backup\.tar\.bz2//";
//preg_quote使用
$pat = "/" .
preg_quote("../hoge/piyo-fuga/[07-02-02](subtitle)backup.tar.bz2", "/")
. "/";
このように、エスケープすると見づらくなるソースもわかりやすくなります。
ひとつエスケープを忘れたのに気づかずに誤動作を起こして、デバッグに時間が かかってしまうなどのリスクを軽減できます。
ループ文を使用してエスケープ処理を書くより、この関数を使ったほうが無駄な手間を省いてスマートに記述できます。
もし、preg系関数のエスケープ処理を書く機会があれば、使ってみてはいかがでしょうか。
バックナンバーについて
TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。




