PHPで文字列を抽出するにはsubstr()
を使いますが、日本語の扱いで、なぜか数が合わずにハマってしまう人も多いでしょう。
substr()
の基本的な使い方からmb_substr()
を使い、日本語でも適切に抽出できる方法もご紹介します。
目次
substr関数で抽出
文字列の一部を取得します。バイト数で数えるため、日本語の処理は数が狂います。
substrの基本的な使い方
1 2 3 4 5 6 |
// ファイル名を変数に格納 $img = '12345678.jpg'; // substrで5文字目以降を抽出 // oから始まるので、4は5文字目になる echo substr($img, 4); |
5678.jpg
開始位置は0から数えるため、第二引数に4
を指定すると5文字目が開始位置となります。
substrの構文
substr ( 抽出元の文字列 , 抽出開始位置 (, 抽出文字数(省略可)) );
抽出したい文字列の開始位置は0から始まる数値で指定します。
先頭から抽出する場合0
となります。
負の数を指定すると、文字列の最後から数えます。
抽出文字数は省略可能で、0スタートではなく、開始位置から抽出したい文字数を指定します。
substrのさまざまな使い方
先頭から8文字を抽出
1 2 3 4 5 6 |
// ファイル名を変数に格納 $img = '12345678.jpg'; // substrで0文字目から8文字分を抽出 // 最初の数値は0から始まり、最後の数値は実際に何文字抽出するかを指定 echo substr($img, 0, 8); |
12345678
開始位置は0
なので先頭で、第三引数の2つ目の数値は何文字抽出するかを表しています。
8
なので、8文字抽出するという意味です。
第三引数は0スタートではありません。
最後から4文字目以降を抽出
1 2 3 4 5 |
// ファイル名を変数に格納 $img = '12345678.jpg'; // substrで最後から4文字目以降を抽出 echo substr($img, -4); |
.jpg
第二引数に負の数が指定されると、最後から数えるため-4
は最後から4文字目以降を抽出します。
これも0スタートではありません。
3文字目からを抽出し最後の4文字を削除
1 2 3 4 5 |
// ファイル名を変数に格納 $img = '12345678.jpg'; // substrで3文字目からを抽出し、最後の4文字を削除 echo substr($img, 2, -4); |
345678
第三引数に負の数が指定されると、最後からその文字数分削除されます。
最初と最後の除外する文字数が決まっていて、抽出文字数はバラバラな場合に使えますね。
substrで日本語が文字化け
substr()
はバイト数を数えます。
アルファベット用の関数なので、日本語などのマルチバイト文字列だと文字数が狂ったり、文字化けを起こします。
1 2 3 4 5 |
// 日本語を変数に格納 $str = 'あのイーハトーヴォのすきとおった風'; // 日本語が入った変数をsubstrで処理すると文字化け echo substr($str, 2, 7); |
�のイ
上記のように文字化けしてしまいました。文字数も合っていません。
substr()
は文字数ではなくバイト数で数えるため、日本語は2バイト以上になることが多く、このような結果になりました。
日本語を処理する場合、下記mb_substr()
を使いましょう。
mb_substr関数で日本語を抽出
文字数で数えてくれるので、日本語の処理も可能です。
mb_substrの基本的な使い方
1 2 3 4 5 |
// 日本語を変数に格納 $str = 'あのイーハトーヴォのすきとおった風'; // mb_substrでutf8エンコードで処理 echo mb_substr($str, 2, 7, 'utf8'); |
イーハトーヴォ
mb_substr()
で日本語もきちんと抽出できましたね。
mb_substrの構文
mb_substr ( 抽出元の文字列 , 抽出開始位置 ( ,抽出文字数(省略可)( , エンコード(省略可))) );
エンコードは省略可能で、エンコードを省略した場合、内部エンコードが適用されます。
抽出文字数が省略されていた場合、エンコードを指定することはできません。
mb_substrでも日本語が文字化けする場合
mb_substr()
のエンコードを省略すると、日本語が文字化けする場合があります。
1 2 3 4 5 |
// 日本語を変数に格納 $str = 'あのイーハトーヴォのすきとおった風'; // エンコードを省略 echo mb_substr($str, 2, 7); |
�のイ
utf8のエンコードを省略すると上記のように文字化けしました。
mb_substr()
のエンコードを省略すると、php.iniの内部エンコードの設定が反映されます。
わたくしの環境ではno value
となっていたため、substr()
と同様の結果となってしまいました。
日本語を処理する場合は、きちんとエンコードも指定しましょう。
ドキュメントと異なるエンコードを指定しても文字化けする
コードを記載したドキュメントの文字列エンコードとmb_substr()
のエンコードが異なる場合、やはり文字化けします。
1 2 3 4 5 6 7 8 |
// ドキュメントのエンコードをUTF-8に設定 header("Content-Type: text/html; charset=UTF-8"); // 日本語を変数に格納 $str = 'あのイーハトーヴォのすきとおった風'; // mb_substrのエンコードをドキュメントと違うshift_jisで指定 echo mb_substr($str, 2, 7, 'sjis'); |
��イーハ�
utf8でエンコードされたドキュメントにmb_substr()
をshift_jisのエンコードで記述すると、やはり文字化けしました。
ドキュメントとmb_substr()
のエンコードは統一しましょう。
ちなみに、webのエンコードは以前はshift_jisが主流でしたが、現在ではUTF-8が主流となっています。
特別な理由がなければ、UTF-8で統一してしまいましょう。
正規表現で抽出
preg_replaceで抽出
正規表現なら思うような抽出もできますが、多少処理が重くなるため、なるべくsubstr()
をオススメしています。
1 2 3 4 5 |
// ファイル名を変数に格納 $img = '12345678.jpg'; // 正規表現で数値以外を空文字に変換 echo preg_replace('/[^0-9]/', '', $img); |
12345678
正規表現で数字(0〜9)以外を空文字に変換、つまり削除して、結果的に数字だけ抽出できました。
ただ、正規表現は処理が重いためsubstr()
では難しい処理などに限定して使いたいですね。