機能概要
MySQL utf8mb4
utf-8は過去の歴史的経緯から1文字を表すための文字列長が1~3バイトの時代から1~4バイトになっている。(※1)
MySQL5.7までの'utf8'はutf8mb3のエイリアスで、1~3バイトのutf-8しか保存できない。
4バイト以上を格納する場合はutf8mb4を文字コードに設定する必要がある。
なお、MySQL8.0では、デフォルトはuft8mb4である。
そのため、utf8と定義するとutf8mb4に紐づくが、utf8mb4と書く方が安全かと思う。
※1
過去一律3バイトであったとか、5・6バイト問題はここでは割愛する。
詳しく知りたい人は、ユニコード戦記とかを読んでもらえれば。。
調査したかったこと
utf-16で取り扱うサロゲートペア文字になる範囲と、utf-8mb4で取り扱うサロゲートペア文字な範囲が実はずれがないのか気になり調査した。
utf-8の各バイト単位の下限と上限値
| バイト数 | 下限 | 上限 | unicode下限 | unicode上限 |
|---|---|---|---|---|
| 1バイト | 00 | 7F | U+0000 | U+007F |
| 2バイト | C280 | DFBF | U+0080 | U+07FF |
| 3バイト | E0A080 | EFBFBF | U+0800 | U+FFFF |
| 4バイト | F0908080 | F48FBFBF | U+10000 | U+10FFFF |
utf-16の通常文字とサロゲート文字の下限と上限値
| バイト数 | 下限 | 上限 | unicode下限 | unicode上限 |
|---|---|---|---|---|
| 2バイト | 0000 | FFFF | U+0000 | U+FFFF |
| 4バイト | D800DC00 | DBFFDFFF | U+10000 | U+10FFFF |
結果、utf8mb4はutf-8の4バイト目を扱うための文字コードである事が分かった。
(4バイト目の値が、unicodeでは同じ文字範囲(u+10000~u+10FFFF)を指すため、UTF-8及びUTF-16では同じ値になっていることが分かる)
また、サロゲートペア文字でない箇所において、utf-8では1~3バイトの可変長で表現している。
一方、utf-16では一律2バイトで表現しているため、上記の様な値の違いが発生する。
補記事項
UTF-8で許されていない文字コードの値
調査したタイミングでは、UTF-8に関して、以下が許されてない模様である。
- 2バイト表現:下限値の第一オクテットがC0~C1
- 4バイト表現:上限値の第一オクテットがF4~F7
面
3バイト文字までがUnicodeでは、第0面と呼び、4バイト文字は現在第1面~第16面として定義されている。
但し、第4面~第13面は現時点では未定義である。
https://ja.wikipedia.org/w/index.php?title=Unicode§ion=10#%E9%9D%A2
unicodeで表現できる最大値
将来的に利用できるいう意味で、色々なサイトでu+110000~u+1FFFFFもunicodeの最大値として紹介しているサイトを見かける。
しかし、現時点ではu+10FFFFがunicodeの最大値である。
まぁ、いずれ将来は使いきることもあるであろうから、言葉のあや程度で考えておけば良い。
The Unicode Standard supports three character encoding forms: UTF-32, UTF-16, and UTF-8. Each encoding form maps the Unicode code points U+0000..U+D7FF and U+E000..U+10FFFF to unique code unit sequences.
(Unicode CONSORTIUM Unicode 13.0.0 3.9 Unicode Encoding Forms より抜粋)
http://www.unicode.org/versions/Unicode13.0.0/ch03.pdf
Javaの内部エンコーディングがUTF-16BEと記載されているドキュメント
正確にはUTF-16とまでしか書かれておらず、UTF-16BE[ビック・エンディアン]と書かれている箇所が見つけれなかった。
Charset (Java SE 11 & JDK 11 )
UCS-4
ざっくり言うとサロゲートペア文字のこと
UCS-2がBMPでU+0000~U+FFFFの文字のこと
なお、UCS-2とUCS-4はもうオワコンな言い方(※2)
※2
RFC3629 12. Changes from RFC 2279 より
Straightened out terminology.
UTF-8 now described in terms of an encoding form of the character number.
UCS-2 and UCS-4 almost disappeared.
RFC 3629 - UTF-8, a transformation format of ISO 10646 日本語訳
通信用語の基礎知識 UCS-2 UnicodeとUCS-2 より
ISO/IEC 10646誕生の経緯から、Unicodeに配慮してこの「UCS-2」という用語が生まれたが、Unicode用語としては既に廃止されている。
Oracle Databaseにおけるutf-8対応
AL32UTF8というのを利用する必要があるのだが、以下の様な経緯があるため。
現在のOracle Databaseでも、CESU-8を「UTF8」として、「普通のUTF-8」を「AL32UTF8」として扱っているため注意を要する。
MySQLでも「utf8」を指定した場合は4オクテット列が扱えず、CESU-8相当の符号化を必要とする
(4オクテット列対応のUTF-8は「utf8mb4」として別途定義されているが、MySQL 5.5.3以降でないと使用できない[9])。
(wikipedia UTF-8 サロゲートペアの扱い より抜粋)
UTF-8 - Wikipedia
CESU-8
UTF-8の黒歴史の一つっぽい。
Unicode 暗黒面
サロゲートペア文字への向き合い方
日本語を扱う人にとっては、漢字が間違いなくサロゲートペア文字問題が付きまとう。
最近なら絵文字(※3)も影響してくる。
なお、データベースでutf8mb4管理できても、アプリ側でサロゲートペア対応できてないと片手落ちである。
例えば、Javaはlengthメソッドで文字数を数える実装がどこかに存在する。
lengthメソッドはサロゲートペア文字に対応していないメソッドのため、基本その記述があるJavaアプリはアウトである。
そのため、Javaの世界だけで考えるとサロゲートペア文字をまともに扱えるシステムはまだまだ少数と思う。
また、それらも踏まえたうえで、どう取り扱うのか決定しないといけない。
※3
絵文字もサロゲートペア文字で表現しないと駄目な絵文字と、サロゲートペア文字で無くても使える絵文字がある。
そのため、絵文字扱える=サロゲートペア対応されていると考えるのは短絡的なので注意する必要がある。
yoneyore.hatenablog.com

![[改訂新版]プログラマのための文字コード技術入門 (WEB+DB PRESS plusシリーズ) [改訂新版]プログラマのための文字コード技術入門 (WEB+DB PRESS plusシリーズ)](https://m.media-amazon.com/images/I/51vqn-2eVKL._SL500_.jpg)
