Movatterモバイル変換


[0]ホーム

URL:


LoginSignup
610

Go to list of users who liked

237

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UTF-8のテーブル(MySQL5.6)に竈門禰󠄀豆子が格納できない問題を調べてみた

Last updated atPosted at 2021-03-27

竈門禰󠄀豆子をMySQL5.6のテーブルにinsertしようとすると正しく格納できず、竈門禰となってしまうケースがあるという話を聞き、調べてみました。

実践

まずは試しにやってみます。

mysql>showcreatetableverification\G***************************1.row***************************Table:verificationCreateTable:CREATETABLE`verification`(`name`varchar(100)COLLATEutf8_binDEFAULTNULL)ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_bin1rowinset(0.01sec)mysql>insertintoverification(name)values('竈門禰󠄀豆子');QueryOK,1rowaffected,2warnings(0.01sec)mysql>select*fromverification;+-----------+|name|+-----------+|竈門禰|+-----------+1rowinset(0.00sec)

確かに竈門禰になっていることがわかりました。

調査

文字コード周りの設定を見てみます。

mysql>SHOWVARIABLESLIKE'char%';+--------------------------+----------------------------+|Variable_name|Value|+--------------------------+----------------------------+|character_set_client|utf8||character_set_connection|utf8||character_set_database|utf8||character_set_filesystem|binary||character_set_results|utf8||character_set_server|utf8||character_set_system|utf8||character_sets_dir|/usr/share/mysql/charsets/|+--------------------------+----------------------------+8rowsinset(0.01sec)

テーブルの文字コード設定はutf8です。公式リファレンスにも記載がありますが、MySQLのutf8文字セットは、3byteまでの文字を扱うことができます。

mysql>select*fromCHARACTER_SETSwhereCHARACTER_SET_NAMElike'utf8%';+--------------------+----------------------+---------------+--------+|CHARACTER_SET_NAME|DEFAULT_COLLATE_NAME|DESCRIPTION|MAXLEN|+--------------------+----------------------+---------------+--------+|utf8|utf8_general_ci|UTF-8Unicode|3||utf8mb4|utf8mb4_general_ci|UTF-8Unicode|4|+--------------------+----------------------+---------------+--------+2rowsinset(0.00sec)

というわけで、文字が途中で途切れて格納されるのは文字コードの設定がutf8であることが一因のようです。

ただ、素直に考えるなら竈門禰で途切れているのでがutf8で扱えない4byte文字ということになります。こんなメジャーな漢字が4byte文字とは到底思えません。確認してみると、

>>>len(''.encode('utf-8'))3

やっぱり3byteでした。そうなると疑わしいのは禰󠄀です。

よくよく見てみると、insertしようとした竈門禰󠄀豆子に対し、実際に登録されたのは竈門禰となっていて、偏がからに変わっていました。何故こんなことが起きるのでしょうか?

禰󠄀について掘り下げて調べてみます。

>>>len('禰󠄀'.encode('utf-8'))7

7byte…?テーブル格納後のを見てみると…

>>>len(''.encode('utf-8'))3

3byteになっています。insertのタイミングで4byteの何らかの情報が欠落してテーブルに格納されたようです。
禰󠄀は一体何者なのか、Unicodeのコードポイントを調べてみます。

>>>ord('禰󠄀')Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:ord()expectedacharacter,butstringoflength2found#2文字??>>>s='禰󠄀'>>>list(s)['','󠄀']>>>foriinlist(s):...hex(ord(i))...'0x79b0''0xe0100'

16進表現で0x79b00xe0100の2文字で構成されていることがわかりました。
0xe0100を調べてみると、これは異体字セレクタというもののようです。Wikipediaによれば、

異体字セレクタ (英: Variation Selector) は、Unicode および ISO/IEC 10646 (UCS) における、文字の字体をより詳細に指定するためのセレクタ (選択子) である。

とあり、を基底文字として偏が異なる文字であることを表現するためのセレクタが含まれていることがわかりました。

まとめ

なぜ竈門禰󠄀豆子がinsert時に一部欠落するかというと、

  • utf8のテーブルには4byte文字を格納できない
  • 禰󠄀の異体字であり、 + 4byteの異体字セレクタの組み合わせで表現される
  • したがって、禰󠄀を格納しようとすると、4byteである異体字セレクタのみ欠落して格納されてしまう

ということでした。異体字セレクタは今まで全く存在を知らず、文字コードの世界は奥が深い、、、と思わされる結果になりました。

追記

この問題を回避したい場合、4byte文字を扱えるutf8mb4を使いましょう。
(参考:https://dev.mysql.com/doc/refman/5.6/ja/charset-unicode-utf8mb4.html

なお、MySQL8系ではutf8mb4がデフォルトのようです。
(参考:https://dev.mysql.com/doc/refman/8.0/ja/server-system-variables.html#sysvar_character_set_client

610

Go to list of users who liked

237
5

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
610

Go to list of users who liked

237

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?


[8]ページ先頭

©2009-2026 Movatter.jp