👆の記事に続き、文字コードに関する本を読んで勉強したことをメモします。読んだ本はこれ👇です。
以下、メモです。
絵文字
imodeとかの時代にJIS X 0208の未定義領域に携帯電話キャリア各社が独自に定義したのが最初。その後Unicodeに取り込まれた。文字と同じように、符号位置は定義しているがそのデザインまでは定義しておらず、送信者と受信者が同じデザインの絵文字を見ているとは限らない。
複数符号位置による装飾が可能で、【白黒の絵文字+絵文字スタイル符号(U+FE0F)】でカラフルな絵文字になったり、【人絵文字+肌の色】で肌色を調整できたり、また【女性👩+コンピュータ💻】で女性テクノロジストを表現できたりする。
UTF-16とBOMとUTF-8
UTF-16は16ビット単位である。そのとき上位8ビットと下位8ビットのどちらを先にデータで表現するかを決めないといけない。例えば「文」はU+6587だが、これを上位を先にすれば “65 87”、下位を先にすれば”87 65”。上位8ビットが先にくるものをビッグエンディアン(big-endian)と呼び、下位が先であればリトルエンディアン(little-endian)と呼ぶ。ビッグエンディアンのUTF-16をUTF-16BE、リトルエンディアンのものをUTF-16LEと呼ぶ。 これらのどちらを採用しているかを示すためにデータの先頭にバイト順マーク(BOM/Byte Order Mark)をつけることがある。BOMにはU+FEFFの符号位置を用い、ビッグエンディアンではデータの先頭に”FE FF”、リトルエンディアンでは”FF FE”というバイト列を付加することになる。
UTF-8にはBOMは必要無いが、ついている場合があり、それを想定していない実装だと予期せぬ結果になることも。
文字コード判別技術
ファイルを開いたとき、それがどんな文字コードで書かれているかを判別する技術について。
BOMによる判別
Unicodeの符号化方式の判別にはBOMを使える
- FE FF xx xx : UTF-16BE
- FF FE xx xx : UTF-16LE
- 00 00 FE FF : UTF-32BE
- FF FE 00 00 : UTF-32LE
- EF BB BF : UTF-8
UTF-8はBOMが無い場合もある。
エスケープシーケンスによる判別
エスケープシーケンスを使うもの(ISO-2022-JP)と使わないもの(Shift_JIS)での判別が可能。さらにエスケープシーケンスの種類によってさらに細かく判別が可能。
バイト列の特徴を読む
たとえば、EUC-JPかShift_JISかを判別するとき、「0x80~0x9Fの値が出てくるようならまず間違いなくShift_JIS」というように使われやすい/にくいバイトといった特徴から読み取ることもできる。
おまけ:正しく判別させるテクニック(文書作成側の話)
うまくプログラムに判別してもらうために、「入」という文字を最初に書いたこともあった。 Shift_JISの「入」のバイトの一部はEUC-JPでは使われず、逆も然りであるため。ただ所詮は小手先のテクニック。
webについて
URLではASCIIを用いる。それ以外の文字はURL符号化(=URLエンコーディング/Percent Encoding)を行う。
URLをHTMLやXMLに書くときにクエリパラメータの区切りの&は&
と書かなければいけない。
- htmlやxmlの文書内部に
<meta charset="utf-8"/>
のように指定をする場合があるが、それを読むにはその文字列の文字コードを分かっておかなければならず、おかしなことになっている。ちょうど箱の中に鍵があるようなもの。現実にはその文字コード宣言はASCIIとして解釈できるようにする、としておくことで対処されている。つまり、ASCII互換の文字コードで解釈すればcharset宣言が理解できるはず、ということ。- とはいうものの、そもそもhttpのレスポンスのヘッダーのContent-Typeでcharsetを宣言すれば正しく伝えられる。
外字と環境依存文字
文字コードで余っている符号に当てはめられた文字を外字という。特にその中でもベンダー定義外字は機種依存文字(環境依存文字)と呼ばれるようになった。当然、文字化けが発生しやすい。
改行コード
2種類あり、CRとLFという名前がついている。利用されるときはそれぞれ1つか組み合わせの3通りがある。 CR : Carriage Return (タイプライターにて紙を右に動かし行頭から印字できるようにすること) LF : Line Feed (紙を上へ動かし次の行へ移動すること) それぞれASCIIではCR→0x0d、LF→0x0aという符号が与えられている。 CRとLFが混ざっていないか意識しながら機能を実装すべし。
CRとLFを動画で見たい場合はこれ😅
全角半角
文字コードは全角や半角を定めていない。文字を表示するプログラム側で1バイトのAと2バイトのAを区別して全角半角を表示しているだけ。 プログラムの利用者が混乱しないように機能開発すべし。
円記号問題
1バイトコードの0x5Cが文字コードによっては¥円マークであったり\バックスラッシュであったりする問題。例えばこのコードは韓国ではウォンを表すコードだったりもする。 HTMLをブラウザで表示する際、charsetをUTF-8にしていたとしてもlang属性によって円マークだったりバックスラッシュだったりが表示される。
試しに自分のPCで 「¥¥\」(全角円、半角円、バックスラッシュ) と売ってみる(UTF-8)と、バイトではそれぞれ 「EFBFA5」「C2A5」「5C」 となった。同じ文字をShift_JISとして保存すると 「818F」「5C」「5C」となり、たしかに円とバックスラッシュの見分けがつかなくなってしまった… つまり、「Shift_JISで円と入力してUTF-8で閲覧した場合にバックスラッシュとなってしまう」ということになる。 確認のためShift_JISで「¥\」と入力して再度UTF-8とShift_JISで開き直すとどちらも「\\」となってしまった…破綻しとるやないか😅