カルキチブログ

マルチバイト文字って何?|PHPのstrpos()とmb_strpos()を使って解説してみました

この記事を書こうと思ったきっかけは、業務で「特定の文字列が含まれているか否かで」処理を分けるコードを書く機会がありまして、僕は普段の業務ではPHPを書いているので、「文字列が含まれてるかどうか調べるメソッドね〜。なんかあるっしょ〜!」って思ってググったらタイトルに含まれているstrpos()とmb_strpos()というメソッドが出てきました。

この2つのメソッドってどう違うん?って思ってググって出てきたサイトには以下のように書いてありました。

日本語を検索する場合は、マルチバイト版のmb_strpos関数を使いましょう(後述)。

引用:https://webkaru.net/php/function-strpos/

マルチバイト文字って、聞いたことはあるけど何だっけ??

業務中に一回ググりはしたけど、忘れてしまったということで今回は、このマルチバイト文字について調べてみました。

マルチバイト文字とは?

普段の日常生活ではほぼ意識することがないとは思いますが、半角文字と全角文字では保存するときに必要なデータの量が違います。

どういうことかというと、例えば、、、

全角:AA11:;!?

半角:AA11:;!?

同じ文字列、同じ大きさで文字を入力してみましたが、全角は半角の倍くらいのスペースを占領していることがわかるかと思います。

倍くらいのスペースというのがほぼ答えのようなものでして、1バイト(主に半角英数字)では表現できない文字列のことをマルチバイト文字と呼びます。

こんなややこしいことになっているのにはどうやら理由があるらしく、コンピュータの世界では文字列を扱うとき0と1の数字(2進法ってやつ)を組み合わせることで文字列として認識するらしいのですが、0と1の組み合わせが入る一つの箱のようなものが1ビット、1ビットが8個集まると1バイトになるので、2の8乗、つまり1バイトでは256種類のデータを表現できるわけです。

昔のコンピュータは英語圏の人が作ったらしいのですが、英語圏には英数字と記号しかないので、256種類もデータが扱えれば十分そうですよね?

ところが、コンピュータがだんだん普及してきて、日本や中国などアルファベットを使わない言語を使う人たちからも「コンピュータ使いたいんだけど!?」っていう要望が出てくるわけです。

日本語の場合はひらがなカタカナに加えて漢字、中国は漢字オンリーですが、常用漢字が3805種類あるらしいので、256種類で表現するというのはどう考えても無理です。

そこで、頭のいい人たちは考えるわけです。

足りないなら倍にしちゃえばよくねっ!?と、、、

そういう経緯で登場したのが、マルチバイト文字というわけです。

2バイトなら2の16乗で、65536種類、3バイトなら2の24乗で、16777216種類までいけるようになるわけです。

簡潔にまとめるなら半角英数字よりも見た感じスペースとってそうだなーという文字列は、マルチバイト文字という認識で大丈夫なのかなと思います。

→この覚え方が正しいかどうかはちょっと自信がありません。。。

違いを実際に比較してみました

説明が長くなりましたが、最後は実際にコードを書いて1バイト文字とマルチバイト文字の比較をしてみたいと思います。

まずは、strpos()からです。

<?php
    $test_str = 'Hello World!';
    var_dump(strpos($test_str, 'World'));
    var_dump(strpos($test_str, 'hoge'));

これを実行してみるとこうなります。

int(6) bool(false)

PHPのstrpos()は、ある文字列の中から検索対象の文字列が見つかった場合、最初に見つかった位置を数値(開始は0からで1からではない)で返す関数なので、半角スペースも含め6という数値が返ってきています。

一方見つからない場合はboolean型で結果を返すので、hogeに対しては、falseが返ってきています。

では次に、このstrpos()で日本語の検索を行ってみましょう。

<?php
    $test_str = 'カルキチ副島ウルトラファイヤー';
    var_dump(strpos($test_str, '副島'));
    var_dump(strpos($test_str, '山田'));

これを実行してみるとこうなります。

int(12) bool(false)

副という文字列は0から数えて4番目にあるにも関わらず、12という数値が返ってきていますね。

この現象もマルチバイト文字がなんなのか理解ができていれば、割と簡単に理解できます。

僕のローカルにあるPHPの実行環境の文字コードはUTF-8にセットされています。

UTF-8とは、世界的に普及している文字コードの一種です。

UTF-8について詳しく書き出すと、Unicodeについての説明とかも必要になり、これだけで一つの記事が書けそうなので、また気が向いたら書きます。

UTF-8という文字コードでは、全角のひらがなやカタカナ、英数字は3バイト文字として扱う決まりがあります。

副という文字列は0から数えて12番目にあるので、12という数値が返ってくるわけです。

4という数値を返したい場合は、マルチバイト文字を扱えるようにしなければいけないので、strpos()ではなく、マルチバイト文字を扱えるmb_strpos()を使ってみると、、、

<?php
    $test_str = 'カルキチ副島ウルトラファイヤー';
    var_dump(mb_strpos($test_str, '副島'));
    var_dump(mb_strpos($test_str, '山田'));

ちゃんと4という数値が返ってきます!

int(4) bool(false)

strpos()と同じ感覚で扱えるようになりましたね!

文字コードの意識は、正規表現で日本語を置換したいときなどにも必要になるので、覚えておくといいかもしれません!

おまけ

今回マルチバイト文字について調べている過程で、英語圏には全角入力が無いないらしいという情報が出てきて結構驚きました。

→全角入力とは、日本語のワープロ用に用意された文字規格らしく、そもそも英語圏には全角という概念すら存在しないらしいですね。

日本の顔文字は結構凝ったものが多いけど、海外の絵文字は:Dとか、:’)みたいなシンプルで横倒しになっているのが主流なのってこういう背景があるからなのかもしれませんね。