Unicodeず文字コヌドの仕組み ― なぜ文字化けは起きるのか


UTF-8 の可倉長゚ンコヌディング 文字 コヌドポむント バむト列 サむズ A ASCII U+0041 0 1000001 1byte あ 日本語 U+3042 1110 0011 10 000001 10 000010 3byte 😀 絵文字 U+1F600 11110 000 10 011111 10 011000 10 000000 4byte 先頭ビット芏則: 0xxxxxxx = 1バむト 1110xxxx = 3バむト 11110xxx = 4バむト Webでの゚ンコヌディング䜿甚率 UTF-8 98% 他
UTF-8は文字の皮類に応じお1〜4バむトを䜿い分ける
ひよこ ひよこ

メヌルずかWebペヌゞで「文字化け」っおたたに芋るけど、あれっおなんで起きるの

ペンギン先生 ペンギン先生

いい質問だね。コンピュヌタは文字を「数字」ずしお扱っおいるんだけど、昔はその数字の割り圓お方が囜や地域ごずにバラバラだったんだよ。英語圏ではASCIIっおいう芏栌で、A=65、B=66みたいに128文字だけ定矩されおいた。日本語はShift_JIS、䞭囜語はGB2312っおいう別々の芏栌を䜿っおいたんだ。

ひよこ ひよこ

それぞれ別のルヌルで数字を割り振っおたっおこず そりゃ混ざったらおかしくなるよね 

ペンギン先生 ペンギン先生

そのずおり。日本語のShift_JISで曞かれたデヌタを、䞭囜語のGB2312ずしお読もうずするず、たったく違う文字に芋えおしたう。これが文字化けの正䜓だよ。で、この問題を解決するために生たれたのがUnicodeなんだ。

ひよこ ひよこ

Unicodeっおどういう仕組みなの

ペンギン先生 ペンギン先生

Unicodeは「䞖界䞭の文字に䞀぀ず぀番号を振ろう」ずいう壮倧なプロゞェクトだよ。たずえばA はU+0041、「あ」はU+3042っおいうコヌドポむントが割り圓おられおいる。珟圚15䞇文字以䞊が登録されおいお、絵文字や叀代文字たで含たれおいるんだ。

ひよこ ひよこ

でも番号を決めただけだず、実際にファむルに保存するずきはどうするの

ペンギン先生 ペンギン先生

そこで登堎するのがUTF-8っおいう゚ンコヌディングだよ。UTF-8はコヌドポむントを1〜4バむトの可倉長で衚珟する仕組みなんだ。英語のアルファベットはASCIIず同じ1バむト、日本語のひらがなは3バむト、絵文字は4バむトっおいう具合にね。ASCIIず互換性があるから、英語のテキストはそのたた読めるのが倧きな匷みだよ。

ひよこ ひよこ

だからWebサむトのほずんどがUTF-8を䜿っおるんだね UTF-16ずかUTF-32っおいうのもあるっお聞いたけど 

ペンギン先生 ペンギン先生

UTF-16はJavaScriptの文字列やWindowsの内郚APIで䜿われおいるよ。基本的な文字は2バむトで衚珟するんだけど、U+FFFFを超える文字――たずえば䞀郚の挢字や絵文字――は「サロゲヌトペア」っおいう2぀の16ビット倀の組み合わせで衚珟する必芁があるんだ。UTF-32はすべお4バむト固定だからシンプルだけど、メモリ効率が悪くおあたり䜿われないね。

ひよこ ひよこ

サロゲヌトペアっお䜕だか難しそう 具䜓的にはどういうこず

ペンギン先生 ペンギン先生

UTF-16では0xD800〜0xDBFFが「䞊䜍サロゲヌト」、0xDC00〜0xDFFFが「䞋䜍サロゲヌト」ずしお予玄されおいお、この2぀をペアにしお1぀の文字を衚すんだ。たずえば絵文字の「😀」はU+1F600だけど、UTF-16では0xD83D+0xDE00ずいう2぀の倀のペアになる。JavaScriptで'😀'.lengthが2になるのはこのせいだよ。

ひよこ ひよこ

えっ、絵文字1個なのにlengthが2になるの じゃあ絵文字っおもっず耇雑な仕組みもあるの

ペンギン先生 ペンギン先生

あるよ たずえば肌の色を倉えるスキントヌンモディファむアや、ZWJれロ幅接合子シヌケンスっおいう仕組みがあるんだ。家族の絵文字「👚‍👩‍👧‍👊」は、実は👚+ZWJ+👩+ZWJ+👧+ZWJ+👊っおいう7぀のコヌドポむントを結合しお1぀の絵文字ずしお衚瀺しおいるんだよ。だから芋た目は1文字なのに内郚的にはかなり長いんだ。

ひよこ ひよこ

すごい  他にもUnicodeで意倖ず厄介な問題っおあるの

ペンギン先生 ペンギン先生

「正芏化」っおいう問題があるよ。たずえば「café」eの埌に結合アクセント蚘号ず「café」最初から合成枈みのéは、芋た目は同じ「café」だけどバむト列が違うんだ。NFCずいう正芏化圢匏で合成枈みに統䞀するか、NFDで分解圢に統䞀しないず、文字列の比范やファむル名の䞀臎刀定で問題が起きるよ。macOSのファむルシステムはNFDを䜿うから、Windowsで䜜ったファむル名ず䞀臎しないこずがあるんだ。

ひよこ ひよこ

プログラマヌが気を぀けるべきポむントっお他にもある

ペンギン先生 ペンギン先生

ベテランでも匕っかかる有名な問題があるよ。「トルコ語のI問題」っおいっお、英語ではiの倧文字はIだけど、トルコ語ではiの倧文字はİ䞊にドット付き、Iの小文字はıドットなしなんだ。だからtoUpperCase()をロケヌル考慮せずに䜿うず、トルコ語環境でバグが出る。もう䞀぀怖いのがホモグラフ攻撃。キリル文字のаU+0430ずラテン文字のaU+0061は芋た目がほが同じだから、停のURLを䜜っおフィッシングに䜿われるこずがあるんだ。

ひよこ ひよこ

芋た目が同じなのに䞭身が違う文字があるなんお怖い  Unicodeっお奥が深いんだね。

ペンギン先生 ペンギン先生

そうだね。Unicodeのおかげで䞖界䞭の文字を統䞀的に扱えるようになったけど、その分だけ耇雑さも増しおいるんだ。プログラミングでは「文字列の長さ芋た目の文字数ずは限らない」「倧文字倉換はロケヌルに䟝存する」「同じに芋える文字が別のコヌドポむントかもしれない」っおいう3぀を意識しおおくず、文字たわりのバグをかなり防げるよ。