最終更新 2003-11-11
ユニコードで文書を作るとき,文字コードの方式が2種類,あるいはそれ以上あることに気が付かれるかもしれません。例えば,一つはUnicodeとあるのに対し,もう一つはUnicode (UTF-8)と表記されているかもしれません。この2つは,また,その違いは何でしょうか(前者はUTF-16の一形態なのですが…)。
ユニコードが採択されることになった多言語用の文字コードセット,ISO-10846-1は,16ビット(16桁の二進数)でそれぞれの文字を表します。それをUCS-2 (Universal Character Set coded in 2 octets,「2つのオクテットでコードされたユニバーサル文字セット」)と称します。オクテットとは文字長の単位としての8ビット(8桁の二進数)のことです。
ユニコードの特定の文字は,例えば,'A' の文字なら,U+0041
と書いて表記します。UCS-2では,U+0000
からU+FFFF
の文字を用います(可能性を含む)。
また,さらに多くの文字を含められるように4個のオクテットを用いるものをUCS-4といいます。UCS-4では,UCS-2の文字に対応する文字,U+00000000
からU+0000FFFF
に加えて,U+00010000
からU+7FFFFFFF
の文字を含みます(Unicode 3.0では,具体的な文字は確定しておらず,提案の段階のようです)。
UTF (Unicode (or UCS) Transformation Format)とは,これらUCS-2または UCS-4として定義された文字をバイト列(しかし本質的にはビット列かな)としてどのように表現するかの方式を指し,複数の方式があります。
UTF-16は,ユニコード1文字を,常に16ビットで表す文字コードです。[RFC2781]
厳密にいえばUTF-16には3種類あり,それぞれUTF-16,UTF-16BEないしUTF-16LEと呼びます。BEはビッグエンディアン 'Big Endian', LEはリトルエンディアン 'Little Endian' の略です。UCS-2のU+0041
の文字(すなわち 'A')を,UTF-16BEでは00 41
という2バイトで, UTF-16LEでは41 00
という2バイトで表します。
一般的にいえば,UTF-16BEはUCS-2の上位オクテットを先にする方式であり,UTF-16LEは下位オクテットを先にする方式です。
UTF-16では通常,文書の始めにByte Order Mark(BOMと略されます。「バイト順を表す印」というような意味です)を付けます。これはUCS-2でU+FEFF
(UCS-4ならU+0000FEFF
)で表される文字ですが,文書の最初の2バイトをBOMと考え,それがビッグエンディアンのFE FF
なら以降をUTF-16BEのように解釈し,BOMがリトルエンディアンのFF FE
以降をUTF-16LEのように解釈します。
UTF-16,UTF-16BE,UTF-16LEの違いを示すため,'ABC'
という3文字からなる文書の構成を示すなら次のようになります。
00 41 00 42 00 43
41 00 42 00 43 00
FE FF 00 41 00 42 00 43
FF FE 41 00 42 00 43 00
00 41 00 42 00 43
UTF-16BEやUTF-16LEにはBOMは付きません。付いていれば、U+FEFF、すなわち ZWNBSP としての意味を持ちます。もし逆のBOMが付いていたら,ユニコードではU+FFFEという文字は定義されていませんから,誤りのある文書ということになります。
文字コードがUTF-16であるとされる文書で,最初の2バイトがBOMとして解釈できない(FE FF
でもFF FE
でもない)場合,RFC2781によれば,ビッグエンディアンとして解釈されることになっています。
WindowsでいうUnicodeテキストとは,リトルエンディアンのUTF-16です。ビッグエンディアンのUTF-16は,ワードパッドやWordで読もうとしても正しく読めません。ただしInternet ExplorerなどのブラウザでUnicode (Big Endian) として表示し閲覧することならできます。BOMのないものは,今のところ,UTF-16文書として認識されないようです。
UTF-16では,UCS-4にあってUCS-2にない文字のうち,U+10000
からU+10FFFF
の範囲を,(unicode consortiumのいうところの)サロゲートペアとして表します。すなわち,U+D800
からU+DBFF
までの文字を上位サロゲート(high surrogate)とし,U+DC00
からU+DFFF
までの文字を下位サロゲート(low surrogate)として,2つの組み合わせて表現します。そのため,UTF-16では,UCS-4のU+110000以降の文字を表現することができません。
UTF-16で,U+10000
からU+10FFFF
の文字を表す方法を次に示します。
U+10000
は 0x000000に,U+10FFFF
は 0xFFFFFになる。
U' = yyyyyyyyyyxxxxxxxxxx (UCS-4 = U から0x10000だけ差し引いた数) W1 = 110110yyyyyyyyyy (上位サロゲート:D800..DBFFになる) W2 = 110111xxxxxxxxxx (下位サロゲート:DC00..DFFFになる)
例えば,U+12345なら,D8 08 DF 45
と符号化されます(UTF-16BEの場合)。UTF-16LEなら,08 D8 45 DF
の4バイトです。
UCS-2ではASCII文字も含めたあらゆる文字が2バイトで表されます。そうするとASCIIコードとすらも互換性がないので,必ずしも使いやすくありません。そこで,ASCIIとの互換性を保つために作られたのが(これだけの理由ではないかもしれませんが)UTF-8(Unicode (or UCS) Transformation Format, 8-bit encoding form)です。[Unicode Standard 4.0, RFC3629, RFC2279 (obsolete) ならびに RFC2044 (obsolete)]
UCS-2ではASCII文字にはナル文字 00
が必ず付いていたのに対し,UTF-8ではその必要がありません。また,BOMもありません。UTF-8には FE
または FF
といったバイトが含まれることはありません。そのため,UTF-16のBOMと紛れることがありません。
ASCII文字が1バイトで表される代わり,ギリシア文字やロシア文字は2バイト,漢字や仮名などは3バイトになります。UCS-2 (UCS-4) とUTF-8の間には,次の関係があります(U+200000
以降も方法は定義されていますが省略します)。
UCS-2 (UCS-4) | ビットパターン | 第1バイト | 第2バイト | 第3バイト | 第4バイト |
U+0000 .. U+007F | 00000000-0xxxxxxx | 0xxxxxxx | |||
U+0080 .. U+07FF | 00000xxx-xxyyyyyy | 110xxxxx | 10yyyyyy | ||
U+0800 .. U+FFFF | xxxxyyyy-yyzzzzzz | 1110xxxx | 10yyyyyy | 10zzzzzz | |
U+10000..U+1FFFFF | 00000000-000wwwxx- xxxxyyyy-yyzzzzzzz | 11110www | 10xxxxxx | 10yyyyyy | 10zzzzzz |
ご覧の通り,UTF-8では,非ASCII文字にはMSB(最上位ビット)が立った(1になった)コード(二進数で10000000から11111111の文字)を用いるのでASCIIとは完全に区別されます。また,文字の順序は,UCS-2とUTF-8で変わりません。
1バイトの文字は[00-7F]であり,2バイトの文字は[C2-DF]+[80-BF]であり,3バイトの文字は[E0-EF]+[80-BF]+[80-BF]の組み合わせとなります。UTF-8の肝心な点は,1文字が何バイトであるが,先頭バイトを読みこんだ段階で明白に判るという点です。よって,UTF-8の文字列を処理する場合,先頭から順に読みこめば正確に処理できます。逆に,途中から抜き出した部分文字列は,必ずしも正しくは処理できません。
UTF-8として正当なバイト列は,次のようにまとめられます。UTF-16 では表現できない U+D800..U+DFFF
の範囲ならびに U+110000
以降の文字は不正です。
コードポイント | 第1バイト | 第2バイト | 第3バイト | 第4バイト |
U+0000..U+007F |
00..7F |
|||
U+0080..U+07FF |
C2..DF |
80..BF |
||
U+0800..U+0FFF |
E0 |
A0..BF |
80..BF |
|
U+1000..U+CFFF |
E1..EC |
80..BF |
80..BF |
|
U+D000..U+D7FF |
ED |
80..9F |
80..BF |
|
U+E000..U+FFFF |
EE..EF |
80..BF |
80..BF |
|
U+10000..U+3FFFF |
F0 |
90..BF |
80..BF |
80..BF |
U+40000..U+FFFFF |
F1..F3 |
80..BF |
80..BF |
80..BF |
U+100000..U+10FFFF |
F4 |
80..8F |
80..BF |
80..BF |
注意すべきは,C0 80
や E0 80 80
のようなバイト列です。UCSからUTF-8への変換法で,UTF-8が2バイトまたは3バイトになる列と比べると,x,y,zのビットがすべて0になったときに,C0 80
または E0 80 80
となるように見えます。これらはUCS-2のU+0000
と対応するように感じられるかもしれません。
UTF-8 UCS-2 110xxxxx-10yyyyyy 00000xxx-xxyyyyyyC0 80
= 11000000-10000000 → 00000000-00000000 =U+0000
? 1110xxxx-10yyyyyy-10zzzzzz xxxxyyyy-yyzzzzzzE0 80 80
= 11100000-10000000-10000000 → 00000000-00000000 =U+0000
?
しかし,こうしたバイト列は [RFC2279]によれば不正(illegal)であり,認められません。つまりUTF-8では,U+0000
からU+007F
の文字は常に1バイトであり,U+0080
からU+07FF
の文字は常に2バイトでなくてはなりません。
Unicodeでは,往復変換(roundtrip)を保証すべきです。`UTF-8'のC0 80
をUCS-2のU+0000
に対応付けるようなプログラムでは,そのUCS-2を再びUTF-8に変換した時に00
になってしまいます。このような事態は好ましくありません。ですから,C0 80
のような文字列は「不正」とみなさなければなりません。
`UTF-8'のC0 80
をUCS-2のU+0000
に対応付けるようなプログラムでは,例えば,ある種の危険な文字列(命令文など)を除く処理をしたはずなのに,除かれなかったというような事態が起こりえます。ですから,上の表にある文字だけを正当なUTF-8文字と考える必要があります(cf. RFC2279, Security Considerations)。
なお,UTF-16でサロゲートペアとして表現する文字は,UTF-8では4バイトで表します。例えば,UCS-4のU+010000は,UTF-16BE ではD8 00 DC 00
として表現されますが,これをUTF-8で表現する時は,F0 90 80 80
としなければなりません。サロゲートペアを真似て,U+D800,U+DC00の2文字と考えて,ED A0 80 ED B0 80
と6バイトで表すのはいけません。U+D800,U+DC00のようなサロゲートペアの範囲は、Unicode 3.2 以降、不正ですので使ってはいけません。
メールでユニコードを用いることができるように,UTF-7という,7ビットの符号化方式もあります。[RFC2152 ならびに RFC1642 (obsolete)]で述べられています。
UTF-7はBASE64を基礎にした符号化法で,文字列を3種の部分に分けます。
文字 ' ( ) , - . / : ? 10進 39 40 41 44 45 46 47 58 63
文字 ! " # $ % & * ; < = > @ [ ] ^ _ ` { | } 10進 33 34 35 36 37 38 42 59 60 61 62 64 91 93 94 95 96 123 124 125
なお,BASE64のアルファベットは以下の通りです。
Table 1: The Base64 Alphabet [RFC2045] Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y
UTF-7を符号化するには次の手順によって行います。
例:"日本語" という文字列は,U+65E5,U+672C,U+8A9E
だから,+ZeVnLIqe-
と符号化する。
011001-011110-010101-100111-001011-001000-101010-011110 25 32 21 39 11 8 42 30 Z e V n L I q e
例:U+263A
= 001001-100011-1010 は,001001-100011-101000と後ろにビットを補ったうえで,+Jjo-
と符号化する。
UTF-32は,ユニコード1文字を,常に32ビットで表す文字コードです。[Unicode Technical Report #19]
UTF-32とUCS-4の違いは,UTF-32ではUTF-16と同じく,U+0000
からU+10FFFF
までの範囲しか有効ではないことです。つまり,UTF-32はUCS-4のサブセットといえます。
厳密にいえばUTF-32には3種類あり,それぞれUTF-32,UTF-32BEないしUTF-32LEと呼びます。こうくると予想がつくかもしれませんが,これらの違いはUTF-16のと同様です。
UTF-32ではUTF-16のようなサロゲートペアは用いません。U+10203
の文字なら,UTF-32BEでは00 01 02 03
と符号化され,UTF-32LEなら03 02 01 00
として表現されます。
UTF-32ではBOMは,UCS-4のU+FEFF
で表される文字です。文書の最初の4バイトをBOMと考え,それがビッグエンディアンの00 00 FE FF
なら以降をUTF-32BEのように解釈し,BOMがリトルエンディアンのFF FE 00 00
なら以降をUTF-32LEのように解釈します。BOMであれば,それは単にバイト順を表すためのものであって,文書を構成する文字とはみなしません。BOMでなければ,全体がビッグエンディアンであるとみなして解釈します。
UTF-32,UTF-32BE,UTF-32LEの違いを示すため,'ABC'
という3文字からなる文書の構成を示すなら次のようになります。
00 00 00 41 00 00 00 42 00 00 00 43
41 00 00 00 42 00 00 00 43 00 00 00
00 00 FE FF 00 00 00 41 00 00 00 42 00 00 00 43
FF FE 00 00 41 00 00 00 42 00 00 00 43 00 00 00
00 00 00 41 00 00 00 42 00 00 00 43