More Related Content More from Shunji Konishi (20) 文字コードのお話2. 開発者が文字化けなど文字コード関連の問題に直面し
た時にその原因がなんとなく予想できるようになるこ
とを最大の目的とする
正確で厳密な説明をすることは目標としない
◦ 何故なら書いている人にその能力がないから。
◦ 正確な情報を書こうとしても時間の経過とともに変わること
もあるし、(例、JIS X 208の文字数)
◦ 枠組みさえ押さえておけば細かい部分は知らなくても上の目
的は達成できるはず。
技術的な内容のみを述べ文化的な話には立ち入らない
◦ 包摂規準等も対象外
要するにこの文書に書いていることを鵜呑みにしてはいけない
3. 世界中にどれだけの文字があるのか知っている人
が世の中にいないから
◦ 日本語、英語、中国語、韓国語、タイ語、etc..etc…。
メジャーな言語だけでもたくさんある
◦ 日本語ひとつとっても、歴史学者が古典にしか出現しな
い文字を必要と主張したりするし、
◦ さらに異体字とかあったり、 (例、高と髙(ハシゴダカ))
◦ 最近では絵文字も文字と認定されてしまった
言語、歴史、文化など様々な立場がクロスするためある意
味
正解のない問題と言える
4. 歴史をおさえる
日本語コード体系(いわゆるJIS)とUnicodeの違い
をおさえる
文字集合とエンコーディングスキームをちゃんと
区別する
Shift_JISとWindows-31J(MS932)を見極める
◦ 多くの処理系が「Shift_JIS」と言いながら実はMS932を
使用しているため注意が必要
これでほとんどの文字化けは説明できる
5. 1バイトの文字は直線で表す
2バイトの文字は正方形で表す
◦ 縦軸が1byte目(Lead-Byte)
◦ 横軸が2byte目(Trailer-Byte)
それ以外は文章で補足
FF FF
80 80 256 * 256
= 65536
128個の 128*128
= 16384
ポイント
00 00 80 FF
6. わずか94文字(SP,CR,LF等は除く)
◦ 英大文字、小文字、数字、記号
つまり1文字を表すのに7bitで十分
◦ 8bit目は常に0
◦ このように8bit目を使用しない文字コードを「7bitの文字コード」と言
う
◦ 過去には8bit目に独自の意味づけをするアプリもあったらしい
Ex.) 8bit目が「1」の場合はその文字を赤く表示するなど
◦ SMTPサーバーは本来7bitの文字コードしか通さない
FF FF
80 80
94文字を
定義
00 00 80 FF
7. US-ASCIIの未使用領域に半角カナを配置
同じ成り立ちの文字コードとしてヨーロッパ圏で
使用されるIS0-8859-1などがある
0x5CはBACK-SLASHからYEN-MARKに変更
FF FF
いわゆる半角カナ
(0x9F以前と0xE0以降
は未使用) 80 80
US-ASCII
(ただし0x5C=)
00 00 80 FF
8. まったく新しい文字セットを94 * 94の領域に定義
◦ つまりすべての文字は2バイト文字
◦ 英数字、カタカナにも新しい区点を付与
このためそれらの文字はUS-ASCII、JIS X 201とは別のコードポイント
(いわゆる全角文字)
◦ 定義領域を94 * 94としたのは7bitの範囲で収まるようにしたかったか
ら
実際に定義された文字は約6900文字
◦ 数回の改定で文字が追加されたり字形が変わったりしている
◦ 逆に言うと1900文字分程度の未使用領域がある
FF FF
0x21 – 0x7E
80 80 94*94=8836
00 00 80 FF
9. そのまま使うと既存のコード体系(US-ASCII、JIS X
201)との互換性がない
しかし既にそれらの資産があるのでどうにかして互換
性を維持したい
◦ これは日本固有の問題ではなく世界中(主に中国と韓国)で同じ
ような課題に直面していた
エンコーディングスキームの必要性
10. 文字コード = 文字集合 + エンコーディングスキーム
◦ エンコーディングスキームの訳は「文字符号化方式」だがあまりピンと来
ないのでここではエンコーディングスキームという用語を使用する
◦ 文字コードの厳密訳は「符号化文字集合」らしい
文字集合
◦ ある文字コードに含まれる文字として何があるかを定義したもの
(例えば「五十音」は文字集合)
エンコーディングスキーム
◦ ある文字集合(複数の場合もある)をどのように符号化するかを定義したもの
(五十音のエンコーディングスキームとして「ひらがな」と「かたかな」が
ある)
JISの場合
◦ 文字集合: JIS X 201, JIS X 208, JIS X 212, JIS X 213
◦ エンコーディングスキーム: Shift_JIS, EUC-JP, iso-2022-jp
Unicodeの場合
◦ 文字集合: Unicode
◦ エンコーディングスキーム: UTF-8, UTF-16
11. シフトコードによって文字集合を切り替えるエンコーディング
スキーム
◦ 「1B 24 42」が現れたらその先はJIS X 208
◦ 「1B 28 42」が現れたらその先はUS-ASCII
使える文字集合はUS-ASCIIとJIS X 208
◦ つまり JIS X 201(半角カナ)は仕様上使えない
◦ 。。。はずなんだが最近の処理系はほとんど「1B 28 49」でJIS X 201
に切り替わっているらしい(試してみたらJDK6でもそうなっててちょっ
とびっくりした)
何故これがメールで使われるかというと7bitの文字コードだか
FF
ら FF
80 80
00 シフトコード
00 80 FF
による切替
12. 基本は7bit * 7bitの範囲で定義された2byteの文字集合の両方のbyteを
0x80以降にずらすと考えると良い
◦ つまり0x7F以下は1バイト文字、0x80以上はマルチバイト文字となる
◦ このためJIS X 201の半角カナはそのままでは使えない
さらにシングルシフトという仕組みでより多くの文字集合を扱うこと
ができる
◦ シングルシフトとは特定のbyteが現れたらそれに続く1byteまたは2byteは別の文
字集合として解釈する仕組み
◦ 「8E」が現れたらそれに続く1byteはJIS X 201。つまりEUCでは半角カナは
2byte文字
◦ 「8F」が現れたらそれに続く2byteはJIS X 212(後述)。つまり1文字が3byteと
なる
仕様上使える文字集合はJIS X 201, JIS X 208, JIS X 212だが、昔は
3byte文字や2byteの半角カナを正しく扱えるアプリケーションはほと
FF FF
んどなかったので実質JIS X 208しか使えなかった。(今はどうだか知ら
半角カナは
ないが)
シングルシフト
で対応 80 80
00 00 80 FF
13. JIS X 201で作成された文書との完全な互換性を持つことを目的とした
日本独自のエンコーディングスキーム
◦ 1byte目がJIS X 201の空き領域(0x9F以前と0xE0以降)の場合の2byte目の領域に
JIS X 208の文字を再配置
◦ JISコードをずらす(Shift)ことによってできた文字コードなのでShift_JISと言う
2byte目に0x7F以下のbyteが現れるため扱いの難しいコード体系と
なっている
厳密な意味でのShift_JISの文字集合はJIS X 201とJIS X 208のみなので
丸数字などのいわゆる機種依存文字は含まれない
FF FF
いわゆる半角カナ
(0x9F以前と0xE0以降
は未使用) 80 80
00 00 80 FF
14. Shift_JISの空き領域にIBMやNECが独自に追加した文字(いわ
ゆる機種依存文字)をMicrosoftが統合したもの
◦ 代表的な文字は丸数字やローマ数字など
◦ JIS X 208ではなくShift_JISの拡張である点が話をややこしくして
いる
「Windows-31J」という名前はIANAに登録されているが非
推奨
◦ このため多くの処理系が「Shift_JIS」という名前でWindows-31J
を扱っている
FF FF
◦ Javaは両者を厳密に区別しているのがかえって迷惑(--
いわゆる半角カナ
(0x9F以前と0xE0以降 機種依存文字
は未使用) 80 80
00 00 80 FF
15. 7bit * 7bitの範囲に定義された文字集合
◦ JIS X 208から漏れた文字を補完する目的なのでJIS X 208との重複はない
◦ 定義されている文字は約6000文字
EUC-JP,またはUnicodeで使用可能
◦ ISO-2022-JP-1(2)というのもあるらしいが本当に実装があるのかは謎
◦ UnicodeのコードポイントはBMP(非サロゲートペア)の範囲
◦ EUC(3byte文字)を正しく扱えない処理系はまだありそうなのでUnicode
以外では使わない方が無難
FF FF
80 80
00 00 80 FF
16. JIS X 208を拡張する形で再定義された文字集合
◦ JIS X 208のすべての文字を含む
◦ MS932との整合性が考慮されている(外字領域がないなど完全で
はない)
◦ JIS X 212との重複はある
エンコーディングスキームも同時に定義
◦ Shift_JIS, EUC, ISO-2022のそれぞれでのエンコーディングス
キームも規定されたが多分実装されていない
◦ Unicodeでは使用可能だが一部の文字はサロゲートペアとなる
FF FF
80 80
2面を追加
してさらに
文字を追加
00 00 80 FF
JIS X 208の空き領域に文字を追加
17. おそらくMS932をベースにキャリアが独自に絵文
字を追加
◦ とても迷惑
◦ 当然キャリア間での互換性はない
◦ キャリア間ではサーバーでコード変換を行っている(受信
側か送信側かは不明)
Unicode 6.0で絵文字も文字コードに追加された
◦ とても迷惑
◦ 今のところPCへのメール送信でコード変換されている気
配はない(Unicodeではなくiso-2022-jpでの送信)
◦ このまま黒歴史として葬ってもらいたい
18. 本来仕様でサポートされない文字は化けるのが正しい
◦ MS932の機種依存文字
◦ EUC-JPのJIS X 212
◦ ISO-2022-JPに半角カナはない
JISコード間では機械的な可逆変換が可能
◦ 典型的な例としてメールで
送信側ユーザーのメール作成画面でMS932を使用
メール送信時にISO-2022-JPに変換
受信側ユーザーのメール表示画面で再度MS932に変換
◦ としていた場合、変換アルゴリズムが同じであれば文字化け
なしで元の文章が復元されることはありうる
JISとUnicodeの変換では必ず変換テーブルが必要
◦ Javaはコード変換時に一度Unicodeになるので必ず化ける
19. ISO-2022-JP
◦ いつの間にやら半角カナ用のシフトコードがある(どうもOutlook
が始めたことを他が追随したらしい)
◦ Java6から「x-windows-iso2022jp」というMS932ベースの
ISO-2022-JPという謎のエンコーディングをサポート
Shift_JIS
◦ 世の中的にはほぼ間違いなくMS932のこと
現状丸数字などは当たり前のように(ISO-2022-JPの)メールで使用
されていたりするのでもはやそれを使うなという説明に理解が得ら
れ
るとは考えにくい
Javaの場合は起動時のオプションで
-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP
-Dsun.nio.cs.map=Windows-31J/Shift_JIS
としてエンコーディング名を差し替えた方が幸せになれ
るかも
20. 世界中の文字をすべて一つのコード体系の中に押
し込めようという壮大な計画
◦ JISは日本人が日本語のためだけに作成したコード体系な
ので成り立ちが全く異なる
当初は2byteの範囲(256*256=65536文字)に全
ての文字を収めようとしていた
◦ あっさり破綻してサロゲートペアという仕組みを導入
JISの文字集合としては以下を収録
◦ JIS X 201
◦ JIS X 208
◦ JIS X 212
◦ JIS X 213
21. 1991/10 Ver 1.0
1996/7 Ver 2.0 サロゲートペア導入
2002/3 Ver 3.2 JIS X 213対応
2010/10 Ver 6.0 絵文字追加
2012年9月現在のバージョンは6.1
あとは文字が増えるだけ
22. BMP(0x0000 – 0xFFFF) UTF16で2byteで表現できる文字
◦ 第0面とも言う
◦ UTF-16のサロゲートペアとなる領域(0xD800 – 0xDFFF)には文字
を定義できない
拡張領域(0x1_0000 – 0x10_FFFF)サロゲートペアとなる文
字
◦ 第1面 ~ 第16面
FF FF
× 16
80 80
100万文字以上
00 80 FF 00 80 FF
収録可能
BMP 拡張領域 Ver 6.1現在
11万文字定義済み
23. US-ASCIIと互換性のあるエンコーディングスキーム
◦ 0x00 – 0x7F (7bitまで)
1byte文字そのまま
◦ 0x80 – 0x7FF(11bitまで)
2byte
110xxxxx – 10xxxxxxx
◦ 0x800 – 0xFFFF (16bitまで)
3byte
1110xxxx – 10xxxxxx – 10xxxxxx
◦ 0x1_0000 – 0x1F_FFFF (21bitまで)
4byte
11110xxx – 10xxxxxx – 10xxxxxx – 10xxxxxx
実際にはUnicodeのコード領域は0x10_FFFFまで
◦ BMPはすべて3byteに収まるが拡張領域の文字は4byteになる
24. BMPの文字はコードポイントそのまま
拡張領域の文字はサロゲートペアとなる
◦ 上位サロゲートの範囲は0xD800 – 0xDBFF (1024個)
◦ 下位サロゲートの範囲は0xDC00 – 0xDFFF (1024個)
◦ 1024 * 1024 = 1,048,576( = 65536 * 16)文字
サロゲートペアをサポートする場合1文字2byte固
定ではないので注意が必要
◦ JavaのCharacterとStringはUTF-16ベースの実装
String#lengthはUTF16のワード数を返す
String#codePointCountは文字数を返す
25. Unicodeでは複数のコードポイントで1文字を表
す仕組みがある
◦ 「が(U+304C)」を「か(U+304B)」+「゛(U+3099)」
とも書ける
Windowsでは結合文字を見かけることはほとんど
ない(尐なくとも日本では)
Mac OS Xではファイル名などに含まれる分解可
能な文字は積極的に分解されるらしい(未検証)
◦ 要するに「が」は常にU+304B U+3099の並びになる
Webフォームやメールからの添付ファイルを扱う
場合には正規化が必要かも?
◦ しかしあまり問題になったという話を聞かないので一般
の人はほとんど気がつかないんだろうと思う
26. 表1:Unicode変換先のコードポイント
Shift_JIS <-> Unicodeの変換テーブルと
MS932 <-> Unicodeの変換テーブルで
いくつかの記号のマッピングが異なる
元の文字 Shift_JISで変換 MS932で変換
~(WAVE DASH) U+301C U+FF5E
∥(DOUBLE VERTICAL LINE) U+2016 U+2225
-(MINUS SIGN) U+2212 U+FF0D
¢(CENT SIGN) U+00A2 U+FFE0
£(POUND SIGN) U+00A3 U+FFE1
¬(NOT SIGN) U+00AC U+FFE2
この問題の対処にも-Dsun.nio.cs.map=…の対処が有効
27. PostgreSQL 8.2.2以降対応
MySQL 5.5.3以降
◦ DB作成時にcharactersetを「utf8mb4」とする必要が
ある
Salesforce NG
IE9 OK
Chrome 21 OK
Firefox 15 OK
Safari 5.1.7 NG(Windows版だけかも?)
◦ Macの最新版は6なのでWindows版は開発終了との噂も
iOS6 OK
28. 特に理由がない限りUTF-8でページを返すのが無
難
ガラケーサイトはShift_JISで作成するしきたり
◦ 慣習に従って「Shift_JIS」と言っているが実際には
MS932
◦ 最近の端末はほとんどUTF-8を解釈しているっぽいが
◦ 古い端末では化けるモノもあるらしい
◦ Playframeworkではこんな問題も
◦ http://blog.flect.co.jp/labo/2012/08/playframewor
k-5a1c.html
(次バージョンで修正される予定)
29. 元々はSMTPが7bitの文字しか通さない仕様だったため
ISO-2022-JPが使用されていた
その後MIMEの導入で8bitの文字コードを7bitにエンコー
ドして送信することが可能になったのでISO-2022-JPにこ
だわる必然性はなくなったが、いまだにその慣習が根強く
残っている
◦ 昔はISO-2022-JPのメールしか処理ができないくさったメールク
ライアントも多かった
個人的にはメールもUTF-8で送っても良いんじゃないかと
は思っているが。。。
◦ いまだにUTF-8を処理できないメールクライアントが残っている
可能性はあるのでリスクはある
◦ (主に携帯関連の処理で)中継サーバーがコード変換を行っている
ことも多い気もするし、そうするとあんまり意味がない。
◦ MS932互換のISO-2022-JPが事実上の標準として幅を利かして
いるのであればもうそれで良いんじゃないかという気もする。
◦ 絵文字対応が可能になるのもヤブヘビだし。