2014年7月10日木曜日

PHPのmb_ereg系関数で文字化けする時に確認すること

今回、実際に使用していた関数はmb_ereg関数で、
日本語(マルチバイト)の文字列を正規表現マッチを行なう関数ですね。

実験した環境は、
内部エンコーディングは「UTF-8」と設定しています。
ファイルは「EUC-JP」で実験してみました。

まずは、普通にmb_ereg関数を使用してみました。
違いが出るかもしれないとおもい、eregも追加しました。

  1. <?php
  2. var_dump(mb_ereg("", "タイトルイと2あああああ"));
  3.  
  4. var_dump(mb_ereg("タイトル", "タイトル2あああああ"));
  5.  
  6. var_dump(ereg("", "タイトルイと2あああああ"));
  7.  
  8. var_dump(ereg("タイトル", "タイトル2あああああ"));
  9.  
  10. //全部trueだと思ってテスト
  11. ?>
結果はこうなりました。
  1. bool(false) bool(false) int(1) int(1) 

「なんでereg関数だけがtrueなんだろうか?」
日本語を使用しているので、
eregではなくやっぱりmb_eregを使ってパターンマッチさせたいと思いますよね・・・
文字コードや日本語問題で悩んだときに、必ず「日本人を辞めたい」と思ってしまうのは僕だけでしょうか?

さぁ・・気を取り直して問題解決のためにいろいろ調べておりました。
原因は簡単なことでした。
「mb_regex_encoding」でマルチバイト対応の正規表現を使用される文字エンコーディングの設定が、
使用エンコードと違うため誤動作をしていたみたいです。

上記の設定をしないでマルチバイト対応の正規表現を使用すると内部文字エンコーディングに設定されてしまいます。
これにより、下記のように記述しました。
  1. <?php 
  2. mb_regex_encoding("EUC-JP");
  3.  
  4. var_dump(mb_ereg("", "タイトルイと2あああああ"));
  5.  
  6. var_dump(mb_ereg("タイトル", "タイトル2あああああ"));
  7.  
  8. var_dump(ereg("", "タイトルイと2あああああ"));
  9.  
  10. var_dump(ereg("タイトル", "タイトル2あああああ"));
  11.  
  12. //今度こそ全部trueだと思ってテスト
  13. ?>
結果
  1. int(1) int(1) int(1) int(1) 
やっと、思い通りに動作してくれました。
「mb_regex_encoding」の設定の存在に気が付けばすぐに解決はできますね。

普段は内部エンコーディングとファイルの文字コードなどは統一された環境が一般的だと思います。そういったときには上記の設定を意識せずに使うことができるのでこの関数を使用して設定の変更を行なうことはないと思います。
しかし、今回の自分の環境がちょっと不思議な環境だったので、
こういった問題が起こりました。

おまけで、気になったのでこんなことをしてみました。
mb_regex_encoding()で文字コードの指定をしないと内部文字エンコーディングに依存するなら、下記のようになっていたら動きそうな気がしてテストしてみました。
  1. <?php 
  2. mb_internal_encoding("EUC-JP");
  3.  
  4. var_dump(mb_ereg("", "タイトルイと2あああああ"));
  5.  
  6. var_dump(mb_ereg("タイトル", "タイトル2あああああ"));
  7.  
  8. var_dump(ereg("", "タイトルイと2あああああ"));
  9.  
  10. var_dump(ereg("タイトル", "タイトル2あああああ"));
  11.  
  12. //mb_eregは「mb_regex_encoding」の指定がないと内部エンコーディングを参照するらしいので、
  13. //内部エンコーディングの設定を変えたらきっと変わって動いてくれるはずだ・・
  14. ?>
結果
  1. bool(false) bool(false) int(1) int(1) 
あれ?見事に期待を裏切ってくれました。

  1. <?php 
  2. mb_internal_encoding("EUC-JP");
  3. print mb_regex_encoding();
  4. ?>
確認で上記のテストをしてみると・・・
「UTF-8」と表示されました。
内部エンコーディングを手動で変更しても、
mb_regex_encodingのデフォルトにはなってくれないみたいです。

関数でも使い方によってはちゃんと動いたり動かなかったりと、
このようなものを見つけたときは不思議とエンジニアの血が騒ぎます。
こういったことが好きな方でつい、
いろんなことをしたくなってしまいます。

http://blog.asial.co.jp/181
http://unimakura.jp/php/phpmb-ereg.html