表紙 / 自作ソフト / 日記 / 宝箱 / サイト情報 / 検索
一般 / 新C言語 / 駄文
一覧 / 本文

UTF FAQ

Last update: 2014/08/09

(c)2000-2003,2007,2013-2014 seclan. All rights reserved.
Homepage: http://seclan.dll.jp/
E-mail: seclan[ここはアトマークに置き換えてください]dll.jp


Q. UTF って何?

 Unicode (または UCS) Transformation Format の略語です。今のところ、UTF-1, UTF-2, UTF-5, UTF-6, UTF-7, UTF-8, UTF-9, UTF-16, UTF-17, UTF-18, UTF-32 があります。しかし、実際使用されているのは、UTF-8, UTF-16, UTF-32 です。

Q. UCS って何?

 Universal Character Set の略語です。ISO 10646 の文字集合をあらわしています。

Q. BE, LE って何?

 UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE のように UTF-XX の後に BE または LE が付くことがあります。これは、その文字コードを表現しているバイナリのエンディアンを明示しています。
 BE (Big Endian)
 LE (Little Endian)
 このように、エンディアンを明示する方式のほかに BOM をファイル先頭に挿入して、暗黙的にエンディアンを識別させる方法もあります。

Q. BOM って何?

 Byte Order Mark の略で、文字コードのエンディアンを判定するために用いられます。コードポイントは U+0000FEFF です。これをファイルの先頭などに挿入することにより自動的にエンディアンを判定できます。ちなみに、U+0000FEFF はゼロ幅空白 (Zero Width Non-breaking Space) をあらわしています。

先頭からの数バイトUTF 名

00,00,FE,FFUTF-32BE
FF,FE,00,00UTF-32LE
FE,FFUTF-16BE
FF,FEUTF-16LE
EF,BB,BFUTF-8


Q. 各 UTF 間では自由に変換できるの?

 それぞれの変換方式が想定している制限を考慮すると次のような順番で変換する必要があります。
UTF-1, UTF-8 (UTF-2), UTF-5, UTF-9, UTF-17, UTF-18 ⇔ UTF-32 ⇔ UTF-16 ⇔ UTF-6, UTF-7
 例えば、UTF-8 を UTF-7 に変換する場合には、まず UTF-32 にして、次に UTF-16 に変換してから、UTF-7 にする必要があります。

Q. UTF の種類についてもう少し詳しく教えて

 次の通りです。

UTF表現可能最大値バイト長(*)別名コメント出典

UTF-1 0x7FFFFFFF1-5-破棄されたISO 10646:1993 Annex G
UTF-2 0x7FFFFFFF1-6UTF-8UTF-8 の昔の名前-

UTF-5 0x7FFFFFFF1-8-DNS への使用を想定draft-jseng-utf5-00.txt: UTF-5, a transformation format of Unicode and ISO 10646 (失効)
UTF-60x0010FFFF1--DNS への使用を想定。UTF-5 の改良版だから UTF-6。UTF の 6bit 版ではない。draft-ietf-idn-utf6-00.txt: UTF-6 - Yet Another ASCII-Compatible Encoding for IDN (失効)
UTF-7 0x0010FFFF1-6-Mail での使用を想定RFC2152: UTF-7 A Mail-Safe Transformation Format of Unicode
UTF-8 0x7FFFFFFF1-6FSS-UTFファイルシステムでの使用を想定RFC2279: UTF-8, a transformation format of ISO 10646
UTF-9 0x7FFFFFFF1-4-36bitワード計算機用RFC4042: UTF-9 and UTF-18 Efficient Transformation Formats of Unicode (2005 Joke RFC)
UTF-160x0010FFFF2,4--RFC2781: UTF-16, an encoding of ISO 10646
UTF-170x0010FFFF8-64bit アーキテクチャ用。UTF-16 の次という意味から UTF-17 だと思われる。 UTF の 17bit 版ではない。draft-whistler-utf17-00.txt: Unicode Transformation Format Seventeen (失効)
UTF-180x0002FFFF, 0x000E0000 - 0x000EFFFF2-36bitワード計算機用RFC4042: UTF-9 and UTF-18 Efficient Transformation Formats of Unicode (2005 Joke RFC)
UTF-320x0010FFFF4--Unicode TR19

 (*)1バイト==8bit (octet)。UTF-9/18 の場合1バイト==9bit (nonet)。また識別用ヘッダを除いた長さ。

Q. UTF-1 はなぜ破棄されたの?

 符号化すると2バイト以降に '/' が現れるのでファイルシステムといっしょに使えない、符号化文字列の途中から検索すると文字の開始位置がわからない、割り算が入るので重くなる、などの問題が UTF-1 を使うと発生しました。この結果が、UTF-2 (後に UTF-8 とされる) の開発につながっていきました。UTF-8 では符号化した2バイト以降には '/' が出現しません。その結果ファイルシステムと一緒に使用することができます。そのようなことから、FSS-UTF (File System Safe UTF) とも呼ばれるようになりました。

Q. UTF の具体的な変換方式を教えて

 次の通りです。ただし U を UCS または Unicode のコードポイントを表すことにします。また Bxx という表現は左にある U の xx ビット目の値をあらわしています。数字の中の _ は見やすくするために便宜上挿入した記号です。
※参考:「漢字」の UTF16 による表現は 0x6F22 0x5B57 です。

UTF-1

変換方法

  1. 次の関数 T を定義します。
    z T(z)
    0x00-0x5Dz + 0x21
    0x5E-0xBDz + 0x42
    0xBE-0xDEz - 0xBE
    0xDF-0xFFz - 0x60

  2. 次のように、U をバイナリ表現に変換します。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000-0000_009FB07B06B05B04B03B02B01B00
    0000_00A0-0000_00FF0xA0  B07B06B05B04B03B02B01B00
    0000_0100-0000_40150xA1+y/0xBE  T(y%0xBE)
    ただし y = U - 0000_0100
    0000_4016-0003_8E2D0xF6+y/0xBE2  T(y/0xBE%0xBE)  T(y%0xBE)
    ただし y = U - 0000_4016
    0003_8E2E-7FFF_FFFF0xFC+y/0xBE4   T(y/0xBE3%0xBE)   T(y/0xBE2%0xBE)   T(y/0xBE%0xBE)   T(y%0xBE)
    ただし y = U - 0003_8E2E

変換例

  • 漢字 (0x6F22 0x5B57) → 変換 → 
    y1=0x6F22-0x4016, y2=0x5B57-0x4016 → 
    y1=0x2F0C, y2=0x1B41 → 
    0xF6+0x2F0C/0xBE2 T(0x2F0C/0xBE%0xBE) T(0x2F0C%0xBE) 0xF6+0x1B41/0xBE2 T(0x1B41/0xBE%0xBE) T(0x1B41%0xBE) → 
    0xF6 T(0x3F) T(0x4A) 0xF6 T(0x24) T(0x89) → 
    0xF6 0x60 0x6B 0xF6 0x45 0xCB → 
    F6606BF645CB

UTF-5

変換方法

  1. 次の表を用いて、U をバイナリ表現に変換します。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000-0000_000F1 B03B02B01B00
    0000_0010-0000_00FF1 B07B06B05B04  0 B03B02B01B00
    0000_0100-0000_0FFF1 B11B10B09B08  0 B07B06B05B04  0 B03B02B01B00
    ...
    1000_0000-7FFF_FFFF1 B31B30B29B28  0 B27B26B25B24  ...  0 B03B02B01B00

  2. 次の表のように、バイナリの対応する文字を変換された値とします。C 言語で書くと、"0123456789ABCDEFGHIJKLMNOPQRSTUV"[バイナリ] の値となります。アルファベットは必ず大文字を使用します。
    バイナリ 0_00000_00010_00100_00110_01000_01010_01100_0111
    変換値 01234567
    バイナリ 0_10000_10010_10100_10110_11000_11010_11100_1111
    変換値 89ABCDEF
    バイナリ 1_00001_00011_00101_00111_01001_01011_01101_0111
    変換値 GHIJKLMN
    バイナリ 1_10001_10011_10101_10111_11001_11011_11101_1111
    変換値 OPQRSTUV

変換例

  • 漢字 (0x6F22 0x5B57) → "MF22LB57" (すなわちバイト列 4D4632324C423537)

UTF-6

この符号方式は、UTF-5 の次のバージョンと言う意味であって、UTF の 6bit 版ではない。IDN の符号化方式の一つのであるので、本来ここに記す必要はないが、参考までに記しておく。基本的な考えは、各文字の上位バイト、もしくは上位ニブルの一致した部分を省略し、変形UTF-5 変換を行う。変形UTF-5 は、各文字の上位にある不要な 0 を無視して変換するという方法である。基本的にドメインのホスト名のような短い文字列を対象としている。

変換方法

  1. 可変長16進符号化(UTF5VAR): 文字の上位から連続するニブル(4bit)の値 0 を除去した値に対し UTF-5 の変換を行う。
    0x1234→0x1234→S234
    0x0123→0x123→H23
    0x0001→0x1→H
    0x0000->0x0→G
  2. 次のように行う。
    mask=0xffff
    if(文字 '-' を除いた文字数が 1 つ){
     //なにもしない
    } else if(文字列中の'-'を除いた各文字の先頭バイトが V で一致している){
     出力("Y"+UTF5VAR(V)) //識別符号 'Y' と共通バイトを出力
     mask=0x00ff
    } else if(文字列中の'-'を除いた各文字の先頭ニブルが V で一致している){
     出力("Z"+UTF5VAR(V)) //識別符号 'Z' と共通ニブルを出力
     mask=0x0fff
    }
    foreach(文字列のそれぞれの文字 C){
     出力(UTF5VAR(C & mask))
    }
    

変換例

  • ユニコード (0x30E6 0x30CB 0x30B3 0x30FC 0x30C9) →
    mask=0xffff →
    文字列中の先頭バイトが 0x30 で一致 →
    V=0x30 → 出力("Y"+UTF5VAR(0x30)) mask=0x00ff →
    出力(UTF5VAR(0x30E6 & 0x00ff))
    出力(UTF5VAR(0x30CB & 0x00ff))
    出力(UTF5VAR(0x30B3 & 0x00ff))
    出力(UTF5VAR(0x30FC & 0x00ff))
    出力(UTF5VAR(0x30C9 & 0x00ff)) → 結果 →
    "Y"+UTF5VAR(0x30)+UTF5VAR(0xE6)+UTF5VAR(0xCB)+UTF5VAR(0xB3)+UTF5VAR(0xFC)+UTF5VAR(0xC9) →
    Y J0 U6 SB R3 VC S9 →
    YJ0U6SBR3VCS9

UTF-7

変換方法

  1. 次の文字集合を定義します。
    名称 定義される文字群
    set_DABC..XYZabc..xyz012..789'(),-./:?
    set_O!"#$%&*;<=>@[]^_`{|}
    set_BABC..XYZabc..xyz012..789+/

  2. SPC (0x20), TAB (0x09), CR (0x0d), LF (0x0a) は、そのまま使用することが許されます。
  3. set_D に出現する文字はそのまま使用することが許されます。また同様に set_O の文字も許されますが、mail システムによっては支障が出ることがあります。
  4. それ以外の文字は、Unicode 文字列として set_B で示される文字を使って符号化します。符号化は UTF-16 で示される 16bit 単位の Unicode 文字列を基本として、base64 (RFC2045) エンコードをします。ただし、バイトが足りなくなったときに付加される '=' 記号は使用せずに、不足した場合は、ビット値 0を必要数補って符号化します。デコードされたときの最終文字が完全な Unicode をなしていないものは捨てます。もしそれが 0 でないなら、不正な形式ということになります。
     符号化した場合、それを表すために先頭にシフト文字 '+' をつけます。この '+' の文字が (修正された) base64 エンコードの開始を示し、set_B 以外の文字 (例えば、CR LF などの制御文字も含む) が出現するまでが符号化されていることを示します。また明示的に終了を示すために、'-' 記号を使うことができます。この場合には '-' 記号は捨てられます。
     特例として、'+-' は '+' 文字を表すことにします。'+' の後に、set_B または '-'以外の文字が続いた場合不正になります。

変換例

  • 漢字 (0x6F22 0x5B57) →
    01101111_00100010 01011011_01010111 → 
    set_D, set_O に当てはまらないので、base64 でエンコードする →
    011011 110010 001001 011011 010101 11 → 
    011011 110010 001001 011011 010101 110000 → 
    27 50 9 27 21 48 → 
    b y J b V w → 
    "+byJbVw-" (すなわちバイト列 2B62794A6256772D)

UTF-8 / UTF-2

変換方法

  1. 次の表を用いて、U をバイナリ表現に変換します。
    U の範囲 (16進)バイト数変換された表現(バイナリ)
    0000_0000-0000_007F1 0 B06B05B04B03B02B01B00
    0000_0080-0000_07FF2 1 1 0 B10B09B08B07B06  1 0 B05B04B03B02B01B00
    0000_0800-0000_FFFF3 1 1 1 0 B15B14B13B12   1 0 B11B10B09B08B07B06   1 0 B05B04B03B02B01B00
    0001_0000-001F_FFFF4 1 1 1 1 0 B20B19B18   1 0 B17B16B15B14B13B12   1 0 B11B10B09B08B07B06   1 0 B05B04B03B02B01B00
    0020_0000-03FF_FFFF5 1 1 1 1 1 0 B25B24   1 0 B23B22B21B20B19B18   1 0 B17B16B15B14B13B12   1 0 B11B10B09B08B07B06   1 0 B05B04B03B02B01B00
    0400_0000-7FFF_FFFF6 1 1 1 1 1 1 0 B30   1 0 B29B28B27B26B25B24   1 0 B23B22B21B20B19B18   1 0 B17B16B15B14B13B12   1 0 B11B10B09B08B07B06   1 0 B05B04B03B02B01B00

  2. バイナリを、変換値とします。

変換例

  • 漢字 (0x6F22 0x5B57) → 
    01101111_00100010 01011011_01010111 → 
    0110_111100_100010 0101_101101_010111 → 変換 → 
    1110_0110 10_111100 10_100010 1110_0101 10_101101 10_010111 →
    1110_0110 1011_1100 1010_0010 1110_0101 1010_1101 1001_0111 →
    E6BCA2E5AD97

UTF-9

PDP-10 などの計算機では、マシンワードが 36bit なので、主に 8bit が単位の既存の UTF-8、UTF-16、UTF-32 では、36 の約数ではないので、無駄なビットが出てしまい、効率がよくありません。そこで 36bit の約数である 9bit 単位の nonet ごとに処理するのが適切になります。それを口実に、2005 年のジョーク RFC (RFC4042) として提案されたのが UTF-9 です。

変換方法

  1. 次の表を用いて、U をバイナリ表現に変換します。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000-0000_00FF 0 B07B06B05B04B03B02B01B00
    0000_0100-0000_FFFF 1 B15B14B13B12B11B10B09B08   0 B07B06B05B04B03B02B01B00
    0001_0000-00FF_FFFF 1 B23B22B21B20B19B18B17B16   1 B15B14B13B12B11B10B09B08   0 B07B06B05B04B03B02B01B00
    0100_0000-7FFF_FFFF 1 B31B30B29B28B27B26B25B24   1 B23B22B21B20B19B18B17B16   1 B15B14B13B12B11B10B09B08   0 B07B06B05B04B03B02B01B00

  2. バイナリを、変換値とします。

変換例

  • 漢字 (0x226F 0x575B) → 
    00100010_01101111 01010111_01011011 → 変換 → 
    1_00100010_0_01101111 1_01010111_0_01011011 → 
    0122006F0157005B

UTF-16

変換方法

  1. 次の表を用いて、U をバイナリ表現に変換します。ただし、U が 0x1_0000 以上の値の場合には、U から 0x1_0000 を引いた値を用います。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000-0000_FFFF B15B14B13B12B11B10B09B08B07B06B05B04B03B02B01B00
    0001_0000-0010_FFFF 1 1 0 1 1 0 B19B18B17B16B15B14B13B12B11B10   1 1 0 1 1 1 B09B08B07B06B05B04B03B02B01B00

  2. バイナリを、変換値とします。16 bit 値をこのままの順に格納すると UTF-16BE となります。バイナリに示される 16bit 値のバイトをそれぞれ逆順にすると UTF-16LE となります。

変換例

  • 漢字 (0x6F22 0x5B57) → 6F225B57

UTF-17

変換方法

  1. 次のように、U をバイナリ表現に変換します。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000 00111000   0 0 1 1 0 B20B19B18   0 0 1 1 0 B17B16B15   0 0 1 1 0 B14B13B12   0 0 1 1 0 B11B10B09   0 0 1 1 0 B08B07B06   0 0 1 1 0 B05B04B03   0 0 0 0 0 B02B01B00
    0000_0001-0010_FFFF 00111000   0 0 1 1 0 B20B19B18   0 0 1 1 0 B17B16B15   0 0 1 1 0 B14B13B12   0 0 1 1 0 B11B10B09   0 0 1 1 0 B08B07B06   0 0 1 1 0 B05B04B03   0 0 1 1 0 B02B01B00

  2. バイナリを、変換値とします。

変換例

  • 漢字 (0x226F 0x575B) → 
    00100010_01101111 01010111_01011011 → 変換 → 
    0_010_001_001_101_111 0_101_011_101_011_011 → 
    00111000 00110000 00110000 00110010 00110001 00110001 00110101 00110111  00111000 00110000 00110000 00110101 00110011 00110101 00110011 00110011 → 
    38 30 30 32 31 31 35 37 38 30 30 35 33 35 33 33 → 
    38303032313135373830303533353333 (このバイナリをダンプすると "8002115780053533" という ASCII 文字列に見える)

UTF-18

PDP-10 などの計算機では、マシンワードが 36bit なので、主に 8bit が単位の既存の UTF-8、UTF-16、UTF-32 では、36 の約数ではないので、無駄なビットが出てしまい、効率がよくありません。そこで 36bit の約数である 9bit 単位の nonet ごとに処理するのが適切になります。それを口実に、2005 年のジョーク RFC (RFC4042) として提案されたのが UTF-18 です。なお、UTF-18 は UTF-9 とは違い、0x2FFFF までのコードポイント、及び 0xE0000-0xEFFFF までのコードポイントしか扱うことができません。

変換方法

  1. 次の表を用いて、U をバイナリ表現に変換します。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000-0002_FFFF B17B16B15B14B13B12B11B10B09   B08B07B06B05B04B03B02B01B00
    000E_0000-000E_FFFF 1 1 B15B14B13B12B11B10B09   B08B07B06B05B04B03B02B01B00

  2. バイナリを、変換値とします。

変換例

  • 漢字 (0x226F 0x575B) → 
    00100010_01101111 01010111_01011011 → 変換 → 
    00_00100010_01101111 00_01010111_01011011 → 
    00226F00575B

UTF-32

変換方法

  1. 次のように、U をバイナリ表現に変換します。
    U の範囲 (16進) 変換された表現(バイナリ)
    0000_0000-0010_FFFF 00000000   0 0 0 B20B19B18B17B16   B15B14B13B12B11B10B09B08   B07B06B05B04B03B02B01B00

  2. バイナリを、変換値とします。このままの順だと UTF-32BE となります。バイナリに示されるバイトの順を逆にすると UTF-32LE となります。

変換例

  • 漢字 (0x6F22 0x5B57) → 00006F2200005B57

表紙 - 著作権 - 注意事項 - リンクについて - 404 エラーについて
(c)2000-2003,2007,2013-2014 seclan. All rights reserved.