PHPをある程度使ってる人なら常識中の常識だと思うんですが・・・
文字数カウントには絶対に strlen 関数は使っちゃダメです。
でも僕自身、PHP初心者の頃は strlen を使ってしまってたことがあります。
そこで過去の恥ずかしい教訓も込めて、
PHPで strlen 関数を使うのが絶対NGな理由と正しいやり方を解説!
このページの目次
なんで文字数カウントには strlen を使っちゃダメなの?
PHPに限らず他言語にも strlen っていう関数はあります。
この strlen っていう名前が本当に紛らわしい・・・
何も予備知識が無いと、
「str、len、、、そうか、文字列(str)の長さ(len)を測る関数か!」
みたいに思っても全くおかしくありません。
でもこの strlen 関数、公式リファレンスを見ると次のように説明されてます。
strlen ( string $string ) : int
与えられた string の長さを返します。注意:
strlen() が返すのはバイト数であり、 文字数ではありません。引用元 : https://www.php.net/manual/ja/function.strlen.php
ご親切にも「バイト数であり、文字数ではありません」とまで書いてくれてます。
とはいえ、半角英数なら1文字1バイトなので、文字数カウントに使っても問題ないです。
例えば次コードみたいに
1 2 3 4 5 |
print_r( strlen('a b c') ); /// => 5 print_r( strlen('hogehoge') ); /// => 8 |
でも日本語などのマルチバイト文字だと問題アリ
次コードみたいに書くと、正しい結果は当然ながら返してくれません。
1 2 3 4 5 |
print_r( strlen('あいうえお') ); /// => 15 print_r( strlen('あア亜') ); /// => 12 |
ちなみに UTF-8 だと、日本語1文字は大体3バイト
なので
strlen * 3 という考え方もできますが、
もし半角・全角混じっているなら、そういう稚拙な方法も通用しなくなってしまいます。
ここまで長々と書いたけど、要するに strlen を使うのは絶対ダメ!
こういうことです。
文字数カウントには mb_strlen を使うのが基本
じゃあ strlen を使っちゃダメなら何を使うかというと、専用の関数が用意されてます。
それが mb_strlen という関数
この関数は公式リファレンスだと、次のように説明されてます。
mb_strlen ( string $str [, string $encoding = mb_internal_encoding() ] ) : int
文字エンコーディング encoding の文字列 str の文字数を返します。 マルチバイト文字の一文字は1個として数えられます。
無効な encoding を指定した場合は FALSE を返します。
引用元 : https://php.net/manual/ja/function.mb-strlen.php
PHPだとデフォルトのエンコーディングは UTF-8 なので、
そのエンコーディング基準での文字数を返してくれるという訳です。
例えば次、これが文字列カウントしてるコード例
1 2 3 4 5 6 7 8 9 10 11 |
/// 半角英数字だけの場合 print_r( mb_strlen('a b c 1 2 3') ); /// => 11 /// 全角文字だけの場合 print_r( mb_strlen('あいうえお') ); /// => 5 /// 半角・全角両方の場合 print_r( mb_strlen('あア亜AaAa') ); /// => 7 |
半角・全角関係なく、文字数でカウントされてるのが分かるはず
何度も言いますが、 strlen という字面に騙されないように要注意です。
基本的な文字数カウントには必ず mb_strlen を使う必要アリ!
もし全角1文字を半角2文字分でカウントしたいなら...
今紹介した mb_strlen は半角・全角関係なく1文字としてカウントします。
でも全角1文字を半角2文字分でカウントしたいこともあるはず
自力でそういうコードを書くこともできるけど、あんまりにも非効率です。
その場合は mb_strwidth 関数を使うのがベスト
この関数についての説明は次の通り
mb_strwidth ( string $str [, string $encoding = mb_internal_encoding() ] ) : int
string str の幅を返します。 半角文字は 1 として、 全角文字は 2 として数えます。全角文字は次のとおりです。 U+1100-U+115F、 U+11A3-U+11A7、 U+11FA-U+11FF、 U+2329-U+232A、 U+2E80-U+2E99、 U+2E9B-U+2EF3、 U+2F00-U+2FD5、 U+2FF0-U+2FFB、 U+3000-U+303E、 U+3041-U+3096、 U+3099-U+30FF、 U+3105-U+312D、 U+3131-U+318E、 U+3190-U+31BA、 U+31C0-U+31E3、 U+31F0-U+321E、...(以下略
引用元 : https://www.php.net/manual/ja/function.mb-strwidth.php
これは 文字の幅 を測るための関数で、全角を半角2文字分としてカウントします。
こういう日本語に優しい関数が用意されてるのもPHPのいいとこですね。
ちなみに以下が mb_strwidth を使ったコード例
1 2 3 4 5 6 7 8 |
print_r( mb_strwidth('あア亜ァAa') ); /// => 10 print_r( mb_strwidth('ABC') ); /// => 6 print_r( mb_strwidth('あ い う え お') ); /// => 14 |
ちなみにこの関数については、次の記事でもチョッとだけ触れました。
▼ Twitter の最大文字数とバイト数を調べてみた
例えば Twitterボット を作るときとか、
日本語1文字を2文字分としてカウントしたいときに使うことが "ごくまれ" にあります。
ここまでのまとめ ~ strlenは絶対に使うな!
ということで、簡単にここまでの内容まとめ
- 文字数カウントに strlen は絶対NG
⇒ これは文字数ではなく、バイト数を数える関数だから
- 文字数カウントには mb_strlen を必ず使う
⇒ 半角・全角関係なく1文字としてカウントしてくれる
- 半角全角区別するなら mb_strwidth を使う
⇒ これは 全角1文字 = 半角2文字 としてカウントしてくれる
以上、PHPで文字数カウントに strlen を使っちゃダメという話でした。
知らないままで使い続けると、痛い目にあうので要注意です!