PHPで文字列の一部を取り出すには substr() と mb_substr() があります。英数字なら substr() で十分ですが、日本語など多バイト文字では substr() を使うと文字化けします。この記事では両者の違いと、正しい使い分けを解説します。
この記事の結論:
substr() はバイト単位、mb_substr() は文字単位で切り出します。日本語を含む文字列は必ず mb_substr() を使ってください。英数字だけなら substr() でも問題ありません。substr:バイト単位で取り出す
substr($string, $start, $length) は、開始位置から指定バイト数を取り出します。位置は0から数えます。英数字(半角ASCII)なら1文字=1バイトなので、見た目どおりに動きます。
substr(英数字なら直感どおり)
<?php $s = "Hello, World!"; echo substr($s, 0, 5); // "Hello" echo substr($s, 7); // "World!"(長さ省略で末尾まで)
注意:substrは日本語で文字化けする
ここが最重要ポイントです。substr() はバイト数で切るため、1文字3バイトのUTF-8日本語では、文字の途中で切れて文字化けします。
NG: 日本語にsubstrを使うと壊れる
<?php $s = "こんにちは、世界!"; // 先頭5文字のつもりが…「こ」(3バイト) + 「ん」の途中2バイト = 文字化け echo substr($s, 0, 5); // "こ" + 壊れたバイト(意図どおりにならない) echo strlen($s); // 25(バイト数) echo mb_strlen($s); // 9(文字数)
「こんにちは」を取りたくて
substr($s, 0, 5) としても、得られるのは「こ」+壊れた1.6文字ぶんのバイトです。日本語の「文字数」で切りたいなら、次の mb_substr() を使ってください。mb_substr:文字単位で正しく取り出す
mb_substr() は文字単位で切り出すため、日本語でも正しく動きます。使い方は substr() とほぼ同じです。
mb_substr(日本語も正しく)
<?php $s = "こんにちは、世界!"; echo mb_substr($s, 0, 5); // "こんにちは"(正しく5文字) echo mb_substr($s, 6); // "世界!"(6文字目以降)
第4引数でエンコーディング(
"UTF-8" など)も指定できますが、省略すると内部エンコーディング(通常UTF-8)が使われます。環境がUTF-8なら省略しても問題ありません。負の開始位置・長さ
開始位置に負の値を渡すと末尾から数えます。長さに負の値を渡すと、末尾からその文字数を残して切り取ります(substr・mb_substr 共通)。
負の値の使い方
<?php $s = "abcdefg"; echo substr($s, -3); // "efg"(末尾3文字) echo substr($s, 0, -2); // "abcde"(末尾2文字を除く) $ja = "あいうえお"; echo mb_substr($ja, -2); // "えお"(末尾2文字)
正確な文字数の取得は文字列の長さを正確に取得する方法、
$str[$i] のような添字アクセスで起こる文字化け・範囲外はUninitialized string offset エラーの解決方法で解説しています。よくある質問(FAQ)
Qsubstrとmb_substrはどう使い分けますか?
A日本語など多バイト文字を含むなら
mb_substr()、半角英数字だけなら substr() で問題ありません。substrはバイト単位なので、日本語に使うと文字化けします。Qsubstrで日本語が文字化けします。
A
substr() がバイト単位で切るためです。UTF-8の日本語は1文字3バイトなどなので、文字の途中で切れて壊れます。mb_substr() を使えば文字単位で正しく切り出せます。Qmb_substrの第4引数(エンコーディング)は必須ですか?
A必須ではありません。省略すると内部エンコーディング(通常UTF-8)が使われます。明示したい場合は
mb_substr($s, 0, 5, "UTF-8") と書きます。Q末尾から数文字を取りたいです。
A開始位置に負の値を渡します。
mb_substr($s, -3) で末尾3文字を取得できます。英数字なら substr($s, -3) でも同じです。まとめ
PHPで文字列の一部を取得するポイントを整理します。
substr()はバイト単位、mb_substr()は文字単位- 日本語を含むなら必ず
mb_substr()(substrは文字化けする) - 位置は0始まり、長さ省略で末尾まで
- 負の開始位置は末尾から、負の長さは末尾を残して切る
- mb_substrの第4引数(encoding)は省略可(既定はUTF-8相当)
関連として、文字列の長さを正確に取得する方法・Uninitialized string offset エラーの解決方法・文字列パターンの確認方法もあわせて読むと、PHPの文字列処理に強くなれます。
