マルチバイト文字列とmb_strlen/mb_substrで日本語を安全に扱う

mb_strlenやmb_substrは、マルチバイト文字列をバイトではなく文字単位で扱う関数です。日本語の長さ計測や切り出しで、文字化けや誤カウントを防ぐための書き方ですね。

strlenが返すのは文字数ではなくバイト数

日本語を扱っていて最初に足をすくわれるのが、strlen が文字数を返してくれない件だと思います。UTF-8 の環境だと全角一文字はおおむね3バイトなので、「あいう」の長さを測ると9が返ってきて、あれっとなるわけですね。

echo strlen('あいう');     // 9(バイト数)
echo mb_strlen('あいう');  // 3(文字数)

入力フォームの文字数制限を strlen で書いてしまうと、日本語ユーザーだけ実質3分の1しか入力できない、みたいな地味に厄介なバグになります。文字数を数えたい場面ではまず mb_strlen だと覚えておくのが無難だと思います。

mb_substrで途中の文字化けを避ける

substr も同じ罠を持っていて、バイト単位で切るせいで全角文字の途中でぶった切って文字化けを起こします。要約の末尾に「…」を付けるような処理は mb_substr で書くのが基本ですね。

$title = '今日の天気は晴れときどき曇り';
// バイトで切ると化ける可能性がある
echo substr($title, 0, 10);       // 文字化けの温床
// 文字単位なら安全
echo mb_substr($title, 0, 6) . '…'; // 今日の天気は…

エンコーディングは明示するのが安全

mb_ 系関数は第二引数以降でエンコーディングを指定できます。省略すると mb_internal_encoding の値が使われますが、環境に依存させたくないので、私は迷ったら ‘UTF-8’ を明示するようにしています。ついでに mb_strwidth を使うと、全角を2・半角を1として幅を測れるので、等幅フォント前提の桁揃えに便利です。

mb_internal_encoding('UTF-8');
echo mb_strlen('ハンカク', 'UTF-8'); // 4
echo mb_strwidth('全角ABC', 'UTF-8'); // 7(全角2×2 + 半角3)

まとめ

日本語が絡む長さ・切り出しの処理は、とりあえず mb_ を付ける癖をつけておくと事故が減ります。strlen や substr が悪いわけではなく、バイトを扱う関数だと理解した上で使い分けるのが大事なところですね。エンコーディングを明示しておくと、環境が変わったときに黙って壊れるリスクも減らせると思います。

よくある質問

Q. strlenとmb_strlenはどちらを使うべきですか。
A. 文字数を数えたいならmb_strlenです。strlenはバイト数を返すので、日本語ではフォームの文字数制限などがずれる原因になります。

Q. mb_系関数のエンコーディングは省略してもいいですか。
A. 省略するとmb_internal_encodingの値に依存します。環境で黙って壊れるのを避けたいので、UTF-8のサイトなら ‘UTF-8’ を明示するのが安全ですね。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です