LoginSignup
1
5

More than 5 years have passed since last update.

マルチバイト文字をpreg_replaceで置換すると増殖することがある

Posted at

こんにちはみなさん

へんてこな挙動に見舞われてキョドったので、その記念に記事書いちゃいます。

何が起こったのか

文書の校正を自動でやるツールをPHP作っている最中、表記ゆれのようなものがあったら、正しいものに書き換える、みたいなものを作っていました。
そのとき、正規表現を置換するのですが、次のような状態になりました。

$ php -a
php > $state = 'あああ';
php > echo preg_replace('/[あ]/', 'o', $state);
ooooooooo

おかしいな、3文字しか置換していないので、9文字に増えてしまったぞ???
ちなみに、

php > $state = 'あああ';
php > echo preg_replace('/あ/', 'o', $state);
ooo
php > $state = 'あああ';
php > echo preg_replace('/(あ|い)/', 'o', $state);
ooo
php > $state = '111';
php > echo preg_replace('/[1]/', 'o', $state);
ooo

となっていて、UTF-8のマルチバイト文字を文字セットで置換したときのみ、このような事象が発生する模様です。
また、この置換の際に文字化けも発生しているようで、判定外の文字が化けたりしました。

php > $state = 'あいうえお';
php > echo preg_replace('/[あう]/', 'え', $state);
えええええ�えええええ�ええ�

もうなにがなんだか。

どうすればいいのか

超単純な話をすれば、問題はマルチバイト文字をちゃんと扱えていないから、だと思われるので、uフラグをつければいいだけですね。

php > $state = 'あいうえお';
php > echo preg_replace('/[あう]/u', 'え', $state);
えいええお

それはいいのですが、なんで普通の置換 preg_replace('/あ/', 'o', $state);は普通に動くのに、文字セットを使った場合にバグるのか。。。
というわけで、日本語を使いそうな場合はuフラグを付けたほうがいいみたいな話...になるのでしょうかね?

多分、文字コードの問題なんだろうなぁと思いつつ、そこまで詳しく確かめる気にもならないので、今回はこのへんで失礼します。

1
5
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5