Top > 文字コード

文字コードについて一般的なことを書きます。言語/ツール依存の個々の例は下記を参照。

目次

ツール Edit

文字コードに携わるときに知っておくと便利なツール。

nkf
日本語の文字コードを変換・判別するUnixコマンド。Windows版もあり。
iconv
文字コードを変換するライブラリおよびコマンド。
日本語以外にも無数のエンコーディングに対応している。
文字コードを判別する機能はない。
文字コード表(charmap.exe)
Windowsのスタートメニューからアクセサリ→システムツール→文字コード表。指定したフォントで利用できる全文字を表示することができる。
「詳細表示」というチェックをオンにするとちょっと機能が増える。
メモ帳
ご存知 notepad。Windows で扱える文字はすべて扱えると思われる。その意味で信頼性が高い。ASCII (SJIS) の他、Unicode (UTF-16) と UTF-8 でも保存できる。
Stiring
Windows のバイナリエディタ。必須。
xxd
Vim に付属のバイナリダンプコマンド。

ファイルに任意のバイト書き込むには Edit

bash Edit

echo -e "\x91\x7b"

917bは「怒」。

vim Edit

<C-v>x91<C-v>x7b

Ruby Edit

[0x91, 0x7b].pack("cc")

用語の定義 Edit

用語定義
文字集合その名の通り、文字の集合。
符号化文字集合文字集合の各文字に対し、番号を割り当てたもの。
文字エンコーディング文字集合をバイト列で表現するマッピングの方法

特に文字集合と文字エンコーディングの使い分けは重要です。はっきり区別して理解しましょう。

たとえば、あるコンピュータでは使える文字が「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 でいうと、

  1. 世界中の文字をリストアップした表が文字集合
  2. その文字にU+xxxxというコードポイントを割り当てたのが符号化文字集合
  3. 文字をファイルに保存したときやネットワークで送信するとき、どんなバイトになるか定めたものが文字エンコーディング。UTF-8やUTF-16BE、UTF-16LEです。

文字集合の種類 Edit

文字集合包含文字詳細情報
ASCII0A# !等。正確には0x00から0xFFまで。http://ja.wikipedia.org/wiki/ASCII
JIS X 0201制御文字・半角英数・半角カナhttp://ja.wikipedia.org/wiki/JIS_X_0201
JIS X 0208ひらがな・記号等・第1水準・第2水準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-2U+0000 から U+FFFF まで。http://e-words.jp/w/UCS-2.html
UCS-4U+00000000 から U+7FFFFFFF まで(全てに文字が割り当てられているわけではない)。http://e-words.jp/w/UCS-4.html
Unicode 1.0
Unicode 2.0

エンコーディングのいろいろ Edit

エンコーディング文字集合備考
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_JISJIS X 0201?の英数字記号、カタカナ、JIS X 0208の漢字、記号などShift_JISはIANAの登録名
ISO-2022-JP
エスケープシーケンスで文字集合を切り替えるため、プログラムの内部コードには向いていない。他機種、他アプリケーション間での通信用に使われる。
EUC-JP
Unixで使われる。Unix環境で問題が起きないように、スラッシュやバックスラッシュなどUnixで特殊な意味を持つ文字が、多バイト文字の2バイト目以降に現れないように設計してある。Shift_JISはそうでないため、0x5C問題がある。

Unicode Edit

Unicode と UCS の違い Edit

  • 定めている団体が違う。Unicode は Unicode コンソーシアム。UCS は ISO。
  • Unicode は文字を U+abcd で表し、UCS は 0xabcd で表す。
    (例:U+2000B 0x0002000B)
UCS-2
0x0000 〜 0xFFFF
UCS-4
0x00000000 〜 0x7FFFFFFF (最上位ビットは必ずオフ)
UTF-16
U+0000 〜 U+10FFFF の 1114112(約110万)個。
U+0000 〜 U+FFFF は2バイトになる。(ただし U+D800 〜 U+DFFF まではサロゲートペアの1バイト目なので、文字は割り当てられていない)
U+10000 〜 U+10FFFF はサロゲートペアを使い4バイトになる。
JavaやWindowsの内部コード。
UTF-8
1〜6バイトの可変長文字エンコーディング方式。ただし現在は4バイトまでしか文字が割り当てられていない。
原理的には UCS-4 のすべての文字を表せる。
ひらがな・カタカナ・漢字は3バイトになる。
ASCIIの拡張なので、既存のデータを流用しやすい。ネットワークでデータを通信したり、テキストファイルに保存するときによく用いられる。
群面区点
UCS-4の範囲を256×256×256×256に分けたもの。
0x0002000B は 00群02面00区0B点となる。
「ぐんめんくてん」と声に出して覚えよう。
なお第0面のことを BMP (Basic Multilingual Plane/基本多言語面)という。

Unicodeのバージョン Edit

■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

OSやミドルウェアの対応状況 Edit

Windows 2000基本的にUnicode 2.0
Windows XPUnicode 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, UTF-16 Edit

UTF-8ASCIIの拡張なので、既存のデータを流用しやすい。ネットワークでデータを通信したり、テキストファイルに保存するときによく用いられる。1バイト~4バイト。原理的には6バイトまでありうるのだが、現在は4バイトまでしか文字が割り当てられていない。
UTF-16JavaやWindowsの内部コード。基本多言語面(BMP)の文字は2バイト、補助文字は4バイト。

Unicode特有の問題 Edit

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での文字のバイト数判定 Edit

乑 ←みたいな文字も見落としてたら
一回データベースサイズオーバーしたバグが過去にありますた。。
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にエンコードした場合何バイトになるか調べなければならない。

UTF-8の場合 Edit

以下、テキストエディタ 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;
}

EUC-JPの場合 Edit

http://ja.wikipedia.org/wiki/EUC-JP
によれば、EUC-JPには主にeucJP-msとCP51932という2種類の亜種が存在する。

ここでは IE で実装されている CP51932 を対象とする。

http://legacy-encoding.sourceforge.jp/wiki/index.php?cp51932
によれば

符号化文字集合cp51932Unicode
1バイト目2バイト目
JIS X 0201 ラテン文字0x00~0x7F---U+0000~U+007F
JIS X 0201 片仮名0x8E0xA1~0xDFU+FF61~U+FF9F
JIS X 0208:19970xA1~0xA8, 0xB0~0xF40xA1~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;
}

HTMLのMETAタグで使う文字コード名 Edit

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

フォームから送信するときの文字コード Edit

フォームから送信するときは、そのページの文字コードが使われる。
(ブラウザによって違うかもしれない。要調査*1
つまり、ページに

 <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">

と書いてあったら、送信するときもShift_JISになる。
では、Shift_JISのページのフォームに、Unicodeにしかない文字を入力して送信したらどうなるだろうか?
例:

ABC乑DEF

という文字を送信すると、サーバ側では

ABC&#20049;DEF

という文字列を受け取る。
20049は0x4E51。Windowsの「アクセサリ」→「システム ツール」→「文字コード表」でU+4E51を見ると「乑」であることがわかる。
つまり、ブラウザ内部では全ての文字をUnicodeで扱っていて、送信の際にUnicode→Shift_JISと変換しているものと推測される。
ただしShift_JISに変換できない文字は文字参照の形で送信するようだ。
ここで、サーバ側が受け取った文字列をそのままレスポンスするようにすると、やはり

ABC&#20049;DEF

が送られ、
ブラウザはこれを受け取ると「ABC乑DEF」を正しく表示できる。

文字データの流れ Edit

MS-IME→ブラウザ→HttpRequest
サーバ処理→HttpResponse→ブラウザが文字コード判定→判定した文字コードからUnicodeへ変換→フォントを使って表示

Windowsカーネルは内部 Unicode。
MS-IME、ブラウザもおそらく内部Unicode。

文字化けしやすい文字一覧 Edit

よく問題となる文字のリスト。

サーブレット             −〜‖¢£¬
JIS X 0201 半角カナ      アイウエオ
JIS X 0208               ①⑪Ⅰ㍉㎜㍻〝〟№㏍℡㊨㈱∫
JIS X 0212               僦 僨 僩 僯 僱 僶
ASCII                    !"#$%&'()-=^~\|
SJISの場合(0x5C)       表ソ十

文字化けじゃないけど
<font color="#ff0000">タグテスト</font>

下記を「ばけもじ」などと単語登録しておくといいかも。

Abカナ漢字,\~-<>&"$①Ⅰ㍉覬鎹

文字化けするかどうかの調査方法 Edit

ウェブシステムで本当にその文字コードの全文字を化けずに扱えるかを試すには、以下のような方法を行えばよい。

create table chartest (
    c varchar(1),
    primary key(c)
);

みたいなテーブルをつくり、
ブラウザからその文字コードにおける全文字を送って、サーバ側でこのテーブルにインサートする。
そして逆にこのテーブルからselectして結果をブラウザに送って確かめればよい。
これをプロジェクトの最初にやっておくといいかも。

肉眼での文字コードの見分け方 Edit

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

ESC(0x1b), $, ( がやたら多かったら JIS っぽいです(これは JIS 特有のエスケープシーケンス)

[~:0]$ echo -n 'あいうえおアイウエオ漢字' | nkf -j | xxd
0000000: 1b24 4224 2224 2424 2624 2824 2a25 2225  .$B$"$$$&$($*%"%
0000010: 2425 2625 2825 2a34 413b 7a              $%&%(%*4A;z

参考リンク集 Edit

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 の解説文書。文字集合、符号化文字集合、文字エンコーディングなど用語の意味についてもきちんと説明されている。

参考書籍 Edit

  • Unicode標準入門
    読んでない。
  • 文字コード超研究
    最初の方は簡単すぎて退屈なので飛ばしてもよし。文字コード個別の詳説には知りたいことがちゃんと書いてある。
    漫然と通して読もうとせず、調べたいことが出てきたときにひもとくのがお勧め。


URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White

*1 formにaccept-charsetという属性があるが、IEでは無視される。

Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup Referer   Help   RSS of recent changes