|
Top > 文字コード 文字コードについて一般的なことを書きます。言語/ツール依存の個々の例は下記を参照。 目次 ツール
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 用語 | 定義 |
| 文字集合 | その名の通り、文字の集合。 |
| 符号化文字集合 | 文字集合の各文字に対し、番号を割り当てたもの。 |
| 文字エンコーディング | 文字集合をバイト列で表現するマッピングの方法 |
特に文字集合と文字エンコーディングの使い分けは重要です。はっきり区別して理解しましょう。
たとえば、あるコンピュータでは使える文字が「A, B, C, ..., Z」で全てであるとします。
これは文字集合です。
文字集合の各文字に番号をふります。
A=1, B=2, C=3, ..., Z=26
これが符号化文字集合です。
さて、このコンピュータで「YES」という文字をファイルに保存するとどんなバイト列になるでしょうか?
Y = 25 (0x19) E = 5 (0x05) S = 19 (0x13)
だから「19 05 13」?
それともこのマシンは32ビットマシンだから「00 00 00 19 00 00 00 05 00 00 00 13」?
それともこのマシンはリトルエンディアンだから「19 00 00 00 05 00 00 00 13 00 00 00」?
どれにしたらいいかわかりませんね。
これを定めるのが文字エンコーディングです。
Unicode でいうと、
| 文字集合 | 包含文字 | 詳細情報 |
| ASCII | 0A# !等。正確には0x00から0xFFまで。 | http://ja.wikipedia.org/wiki/ASCII![]() |
| JIS X 0201 | http://ja.wikipedia.org/wiki/JIS_X_0201![]() | |
| JIS X 0208 | http://www.asahi-net.or.jp/~AX2S-KMTN/ref/jisx0208.html![]() | |
| JIX X 0212 | http://www.asahi-net.or.jp/~AX2S-KMTN/ref/jisx0212/index.html![]() | |
| UCS-2 | U+0000 から U+FFFF まで。 | http://e-words.jp/w/UCS-2.html![]() |
| UCS-4 | U+00000000 から U+7FFFFFFF まで(全てに文字が割り当てられているわけではない)。 | http://e-words.jp/w/UCS-4.html![]() |
| Unicode 1.0 | ||
| Unicode 2.0 |
| エンコーディング | 文字集合 | 備考 |
| ISO-2022-JP | ? | |
| EUC-JP(eucJP-ms ) | ? | Unixで使われる。1バイト目、2バイト目ともに0x80~0xFFの範囲。補助漢字は3バイト。 |
| EUC-JP(cp51932) | JIS X 0201の英数字記号、カタカナ、JIS X 0208、NEC特殊文字、NEC選定IBM拡張文字 | EUC-JPの亜種の1つ。IE、秀丸、EmEditorなどで実装されている。 |
| CP932(MS-932) | ? | マイクロソフトがShift_JISを拡張した。 |
| Shift_JIS | JIS X 0201?の英数字記号、カタカナ、JIS X 0208の漢字、記号など | Shift_JISはIANAの登録名 |
■Unicode側の改訂経緯
Unicode1.0(1991) アメリカの技術者を中心に作られ、漢字コードは極めてデタラメ
Unicode1.1(1993) 中国の技術者が加わり、少しはまともになる。日本が猛反発。
Unicode2.0(1996) 日本や韓国の意見も参考に大規模な漢字のコード移動が行われる。
サロゲートの考えが入って、全てを16bitで表すという理想が崩れた。
25 文字体系 38,885 文字
Unicode2.1(1998) 若干の文字追加
Unicode3.0(2000) 文字の追加
Unicode3.1(2001) 文字の追加
Unicode4.0(2003) 文字の追加
http://www.ffortune.net/comp/develop/data/utf.htm
| Windows 2000 | 基本的にUnicode 2.0 |
| Windows XP | Unicode 3.0 |
Javaについては、Javaのページを参照。
参考:
Java プラットフォームにおける補助文字のサポート
http://java.sun.com/developer/technicalArticles/Intl/Supplementary/index_ja.html
http://mlang1.osaka-gaidai.ac.jp/multi/char_code.html
| UTF-8 | ASCIIの拡張なので、既存のデータを流用しやすい。ネットワークでデータを通信したり、テキストファイルに保存するときによく用いられる。1バイト~4バイト。原理的には6バイトまでありうるのだが、現在は4バイトまでしか文字が割り当てられていない。 |
| UTF-16 | JavaやWindowsの内部コード。基本多言語面(BMP)の文字は2バイト、補助文字は4バイト。 |
Unicodeでは濁点や半濁点の付いた文字、例えば「が」を表すのに二種類の方法がある。
http://www.javainthebox.net/laboratory/JavaSE6/normalizer/normalizer.html
http://blog.ozacc.com/archives/001603.html
YEN SIGN問題、FULLWIDTH TILDE問題
http://ja.wikipedia.org/wiki/Unicode
乑 ←みたいな文字も見落としてたら 一回データベースサイズオーバーしたバグが過去にありますた。。 Javascriptで判定できないのは盲点でした。。 乑のバイト判定 Javascript判定 2バイト Javaでの判定() 6バイト その文字をメモ帳でUnicodeで保存したら4バイト、 UTF-8で保存したら6バイトになりましたが。
Unicodeとは、符号化文字集合を定めたものである。
符号化文字集合とは、文字集合の各文字に対し、重複のないように番号を割り当てたものである。
Unicodeのエンコーディング方式にはUTF-8, UTF-16, UTF-32など色々ある。
Unicodeの同じ文字でもエンコーディング方式によってバイト数は異なるので、
「Unicodeで乑は何バイトか」という表現は意味をなさない。
実際「乑」はUTF-8で3バイト、UTF-16で2バイトである。
メモ帳でこの文字だけを保存すると、UTF-8のときは「ef bb bf e4 b9 91」の
6バイトとなるが、最初の3バイトはBOM(バイトオーダーマーク)であり、「e4 b9 91」
がこの文字である。
同様に「Unicode」で保存すると「ff fe 51 4e」になるが、最初の2バイトはBOMである。
「Javaの内部文字コードはUnicodeである」とよくいわれるが、そのエンコーディング方式は
UTF-16である。しかし下記ページによると厳密には少し違うように読み取れる。
http://java.sun.com/developer/technicalArticles/Intl/Supplementary/index_ja.html
Windowsの内部文字コードもUTF-16である。
さて、JavaScriptのバイト数判定はどんな原理になっているのだろうか?
例えば、↓のページの方法。
http://takeoba.cool.ne.jp/moreJava/javaScript6.htm
おそらくブラウザ内部では全ての文字をUnicodeで保持しているのだろう。
よってcharCodeAt()はUnicodeでの値を返すものと思われる。
実際"乑".charCodeAt(0)は20049を返す。20049は0x4E51であり、Windowsの
「アクセサリ」→「システムツール」→「文字コード表」でU+4E51を見ると
この文字が見つかる(フォントによってはこの文字がないので注意。MS PゴシックならOK)。
このJavaScript関数がやっているのは、Unicodeの状態で文字を調べて、
それを(おそらく)Shift_JISに変換したとき何バイトになるかである。
もしこの文字をUTF-8で保存したときに何バイトになるかを知りたければ、
20049という値からUTF-8にエンコードした場合何バイトになるか調べなければならない。
以下、テキストエディタ Vim のソース(C言語)より抜粋。
JavaScript でもほとんどそのまま使えると思う。
「composing character (合成文字)を含まない」と書いてあるのがちょっと気になるが。
Unicode のコードポイント c が UTF-8 で何バイトになるか。
/*
* Return the number of bytes the UTF-8 encoding of character "c" takes.
* This does not include composing characters.
*/
int
utf_char2len(c)
int c;
{
if (c < 0x80)
return 1;
if (c < 0x800)
return 2;
if (c < 0x10000)
return 3;
if (c < 0x200000)
return 4;
if (c < 0x4000000)
return 5;
return 6;
}
Unicode のコードポイント c を UTF-8 でエンコードする。
/*
* Convert Unicode character "c" to UTF-8 string in "buf[]".
* Returns the number of bytes.
* This does not include composing characters.
*/
int
utf_char2bytes(c, buf)
int c;
char_u *buf;
{
if (c < 0x80) /* 7 bits */
{
buf[0] = c;
return 1;
}
if (c < 0x800) /* 11 bits */
{
buf[0] = 0xc0 + ((unsigned)c >> 6);
buf[1] = 0x80 + (c & 0x3f);
return 2;
}
if (c < 0x10000) /* 16 bits */
{
buf[0] = 0xe0 + ((unsigned)c >> 12);
buf[1] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[2] = 0x80 + (c & 0x3f);
return 3;
}
if (c < 0x200000) /* 21 bits */
{
buf[0] = 0xf0 + ((unsigned)c >> 18);
buf[1] = 0x80 + (((unsigned)c >> 12) & 0x3f);
buf[2] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[3] = 0x80 + (c & 0x3f);
return 4;
}
if (c < 0x4000000) /* 26 bits */
{
buf[0] = 0xf8 + ((unsigned)c >> 24);
buf[1] = 0x80 + (((unsigned)c >> 18) & 0x3f);
buf[2] = 0x80 + (((unsigned)c >> 12) & 0x3f);
buf[3] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[4] = 0x80 + (c & 0x3f);
return 5;
}
/* 31 bits */
buf[0] = 0xfc + ((unsigned)c >> 30);
buf[1] = 0x80 + (((unsigned)c >> 24) & 0x3f);
buf[2] = 0x80 + (((unsigned)c >> 18) & 0x3f);
buf[3] = 0x80 + (((unsigned)c >> 12) & 0x3f);
buf[4] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[5] = 0x80 + (c & 0x3f);
return 6;
}
http://ja.wikipedia.org/wiki/EUC-JP
によれば、EUC-JPには主にeucJP-msとCP51932という2種類の亜種が存在する。
ここでは IE で実装されている CP51932 を対象とする。
http://legacy-encoding.sourceforge.jp/wiki/index.php?cp51932
によれば
| 符号化文字集合 | cp51932 | Unicode | |
| 1バイト目 | 2バイト目 | ||
| JIS X 0201 ラテン文字 | 0x00~0x7F | --- | U+0000~U+007F |
| JIS X 0201 片仮名 | 0x8E | 0xA1~0xDF | U+FF61~U+FF9F |
| JIS X 0208:1997 | 0xA1~0xA8, 0xB0~0xF4 | 0xA1~0xFE | テーブルによる変換 |
| NEC特殊文字 | 0xAD | ||
| NEC選定IBM拡張文字 | 0xF9~0xFC | ||
とのことなので、次のコードでOKだと思う。
function snGetBytesEUCJP(s) {
var c = 0;
var i;
for (i=0; i<s.length; i++) {
if (s.charCodeAt(i) < 0x80)
c += 1;
else
c += 2;
}
return c;
}
IANAという組織が管理している。
http://www.iana.org/assignments/character-sets
Windows-31J (Windows上でSJISとして使っているのはこれ。特に理由がない限りShift_JISでなくこちらを指定する) Shift_JIS (必ずアンダースコア!) EUC-JP (必ずハイフン!) UTF-8
CP932=MS932=MS漢字コード=Windows-31J≒Shift JIS
フォームから送信するときは、そのページの文字コードが使われる。
(ブラウザによって違うかもしれない。要調査*1)
つまり、ページに
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
と書いてあったら、送信するときもShift_JISになる。
では、Shift_JISのページのフォームに、Unicodeにしかない文字を入力して送信したらどうなるだろうか?
例:
ABC乑DEF
という文字を送信すると、サーバ側では
ABC乑DEF
という文字列を受け取る。
20049は0x4E51。Windowsの「アクセサリ」→「システム ツール」→「文字コード表」でU+4E51を見ると「乑」であることがわかる。
つまり、ブラウザ内部では全ての文字をUnicodeで扱っていて、送信の際にUnicode→Shift_JISと変換しているものと推測される。
ただしShift_JISに変換できない文字は文字参照の形で送信するようだ。
ここで、サーバ側が受け取った文字列をそのままレスポンスするようにすると、やはり
ABC乑DEF
が送られ、
ブラウザはこれを受け取ると「ABC乑DEF」を正しく表示できる。
MS-IME→ブラウザ→HttpRequest サーバ処理→HttpResponse→ブラウザが文字コード判定→判定した文字コードからUnicodeへ変換→フォントを使って表示
Windowsカーネルは内部 Unicode。
MS-IME、ブラウザもおそらく内部Unicode。
よく問題となる文字のリスト。
サーブレット −〜‖¢£¬ JIS X 0201 半角カナ アイウエオ JIS X 0208 ①⑪Ⅰ㍉㎜㍻〝〟№㏍℡㊨㈱∫ JIS X 0212 僦 僨 僩 僯 僱 僶 ASCII !"#$%&'()-=^~\| SJISの場合(0x5C) 表ソ十 文字化けじゃないけど <font color="#ff0000">タグテスト</font>
下記を「ばけもじ」などと単語登録しておくといいかも。
Abカナ漢字\~-<>&"$①Ⅰ㍉覬鎹
ウェブシステムで本当にその文字コードの全文字を化けずに扱えるかを試すには、以下のような方法を行えばよい。
create table chartest (
c varchar(1),
primary key(c)
);
みたいなテーブルをつくり、
ブラウザからその文字コードにおける全文字を送って、サーバ側でこのテーブルにインサートする。
そして逆にこのテーブルからselectして結果をブラウザに送って確かめればよい。
これをプロジェクトの最初にやっておくといいかも。
2バイトおきに e3 〜 e9 が出てきたら UTF-8 がくさいです。
[~:0]$ echo -n 'あいうえおアイウエオ漢字青山正太郎' | nkf -w | xxd 0000000: e381 82e3 8184 e381 86e3 8188 e381 8ae3 ................ 0000010: 82a2 e382 a4e3 82a6 e382 a8e3 82aa e6bc ................ 0000020: a2e5 ad97 e99d 92e5 b1b1 e6ad a3e5 a4aa ................ 0000030: e983 8e
ESC(0x1b), $, ( がやたら多かったら JIS っぽいです(これは JIS 特有のエスケープシーケンス)
[~:0]$ echo -n 'あいうえおabcアイウエオ012漢字青山正太郎' | nkf -j |xxd 0000000: 1b24 4224 2224 2424 2624 2824 2a1b 2842 .$B$"$$$&$($*.(B 0000010: 6162 631b 2442 2522 2524 2526 2528 252a abc.$B%"%$%&%(%* 0000020: 1b28 4230 3132 1b24 4234 413b 7a40 443b .(B012.$B4A;z@D; 0000030: 3340 3542 404f 3a 3@5B@O:
Legacy Encoding Project
http://legacy-encoding.sourceforge.jp/wiki/index.php?FrontPage
オープンソースソフトウェアでのレガシーエンコーディング(シフトJIS、日本語EUC、7ビットJISコード)の文字コード変換で生じる問題の解決を目指すプロジェクトです。
Unicodeの名前付き全文字表。
http://www.unicode.org/Public/UNIDATA/NamesList.txt
Java プラットフォームにおける補助文字のサポート
http://java.sun.com/developer/technicalArticles/Intl/Supplementary/index_ja.html
Sun の解説文書。文字集合、符号化文字集合、文字エンコーディングなど用語の意味についてもきちんと説明されている。