文字コードについて調べたことや実験したこと, テストプログラム,データファイルなどを随時掲載する予定です. ただし筆者の理解不足や誤解により誤りがあるかもしれませんので, ご利用は自己責任で.
このページの主な更新は Blog でお知らせします.
表示確認ブラウザ:FireFox 22.0,IE8.
標準的なシフトJIS (以下 Shift_JIS) が扱う2バイト文字は,JIS X 0208 の 1〜94 区であるが,ベンダ独自拡張版のシフトJIS (Windows-31J:Microsoft のコードページ 932 (以下 CP932) など) では,JIS X 0208 には存在しない 95〜120 区も扱う.
シフトJISにおいて,2バイト文字の第1バイト (LeadByte), 第2バイト (TrailByte),区番号,点番号の範囲は次のとおり.
IANA登録名 (別名) |
Shift_JIS (MS_Kanji,csShiftJIS) |
Windows-31J (csWindows31J) |
|
---|---|---|---|
別名 (非IANA) | SJIS(*1) | CP932 | |
位置づけ | 標準版 | ベンダ独自拡張版 | |
収録文字数 | 7,070文字 | 7,517文字 (重複を除く) | |
2バイト文字 | 文字集合 | JIS X 0208 (6,879文字) |
JIS X 0208 (6,879文字) ベンダ拡張文字 (447文字) (ユーザ定義外字領域) (合計7,326文字 (重複を除く)) |
区番号 | 1〜94 | 1〜120 | |
点番号 | 1〜94 | ||
第1バイト (LeadByte) |
0x81〜0x9F 0xE0〜0xEF |
0x81〜0x9F 0xE0〜0xFC |
|
第2バイト (TrailByte) |
0x40〜0x7E 0x80〜0xFC |
||
1バイト文字 | 制御文字 (JIS X 0211 C0集合) (34文字) |
0x00〜0x1F,0x20,0x7F (ASCII 制御文字と同じ.0x20 (空白) は制御 文字とも,印字しない図形文字ともみなされる.) |
|
図形文字 (JIS X 0201) (157文字) |
ラテン文字用図形文字
(ASCII とほぼ互換):0x21〜0x7E 片仮名用図形文字 (いわゆる半角カナ):0xA1〜0xDF |
||
予約 | 0x80,0xA0,0xFD〜0xFF(*2) | ||
未定義 | 0xF0〜0xFC | - |
TrailByte が取りうる値は 188 (=94×2) 通りで, これは点番号の範囲の丁度2倍になるように設計されたものである. つまり一つの LeadByte の値に対して,2区分の符号位置範囲が対応する. したがって LeadByte の取りうる値の範囲は,区番号の範囲の半分 (Shift_JIS では 94/2=47 通り,Windows-31J では 120/2=60 通り) である.
シフトJISの2バイト文字と区点番号は次のようにして対応付けられる.
なお JIS X 0208 の文字については,区番号および点番号それぞれに 0x20 を加算すると JIS コード,0xA0 を加算すると EUC-JP になる.
参考:シフトJIS / JIS X 0208 文字コード表 (現在の表示環境におけるシフトJISの2バイト文字集合を表示)
(*1) | 現実には,“SJIS”や“シフトJIS”などは元の文字集合を区別せず (あるいは区別を理解せず) に標準版もベンダ拡張版もごっちゃにして使われていることが多い. |
(*2) | 0xFD〜0xFF については,数年前に古川享氏 (元・日本マイクロソフト株式会社社長・会長)
のブログの「シフトJISの産まれた歴史的背景」
という記事で次のような内容が書かれていたと思うが,
そのブログは現在削除されているので確認できない.
|
/*───────────────────────────────────── 入力 :byte:0x00〜0xFF. 戻り値:byte がシフトJIS 2バイト文字の第1バイトのときそのときに限り真. 2007/10/28(日) Shift_JIS (1〜94区) 限定版を追加. 2008/06/24(火) 改定 2010/03/18(木) 高速版の不等号の右辺の意味がわかりやすいように定数の表記変更. ─────────────────────────────────────*/ // 定義どおりの素直な判定方法. // (わかりやすいが,範囲の判定方法に無駄があるのであまり賢くない.) // Shift_JIS (1〜94区) 限定版 #define IsSjisLeadByte(byte) \ (ValueInRangeInclusive(0x81U, (unsigned)(byte), 0x9FU) || \ ValueInRangeInclusive(0xE0U, (unsigned)(byte), 0xEFU)) // ベンダ拡張版 (1〜120区) 用 #define IsSjisLeadByteX(byte) \ (ValueInRangeInclusive(0x81U, (unsigned)(byte), 0x9FU) || \ ValueInRangeInclusive(0xE0U, (unsigned)(byte), 0xFCU)) // ┌ここで見つけた巧妙な判定方法. // ↓(上の方法に比べ,条件分岐が2〜4回から1回に減るので少し高速化できそう.) // 初級C言語Q&A(15)【シフトJISの1バイト目の判定】 // Shift_JIS (1〜94区) 限定版 #define IsSjisLeadByte(byte) \ ((((unsigned)(byte) ^ 0x20U) - 0xA1U) < (unsigned)(94/2)) // ベンダ拡張版 (1〜120区) 用 #define IsSjisLeadByteX(byte) \ ((((unsigned)(byte) ^ 0x20U) - 0xA1U) < (unsigned)(120/2)) // 2010/03/05(金) 追記 // この方法は LeadByte を0から始まる連続領域に移動 (「逆」シフト) させるので, // SJIS ⇒ 区点/JIS/EUC 変換に応用すれば判定と変換 (の一部) をまとめて行える. /*───────────────────────────────────── 入力 :byte:0x00〜0xFF. 戻り値:byte がシフトJIS 2バイト文字の第2バイトのときそのときに限り真. 2008/06/24(火) 改定 2010/03/03(水) 条件分岐を1回削減したバージョンを追加. 2010/03/18(木) 高速版の不等号の右辺の意味がわかりやすいように定数の表記変更. ─────────────────────────────────────*/ // 定義どおりの (以下同文) #define IsSjisTrailByte(byte) \ (ValueInRangeInclusive(0x40U, (unsigned)(byte), 0xFCU) && ((unsigned)(byte) != 0x7FU)) // 上の巧妙な方法に倣って,条件分岐を1回削減したバージョン. #define IsSjisTrailByte(byte) \ ((((unsigned)(byte) - 0x40U) < (unsigned)(94 * 2 + 1)) && \ ((unsigned)(byte) != 0x7FU))
1.1 の表に書いてあるとおり, シフトJISには3バイト以上の文字なんか一つもありません!
UTF-8 か EUC-JIS-2004 の3バイト文字とごっちゃになってる?
それともどこかでガセネタ掴まされた?
(この検索ワードは某大手N社とH社 (たぶん子会社を含む)
からのアクセスが多い気がする.
もしかして,これら2社のグループで誰かが嘘を教えているのか?)
「サロゲート (ペア)」は Unicode (正確には UTF-16)
の概念であってシフトJISには関係ありません!
… というツッコミは置いといて …
まあ,Unicode の補助文字 (supplementary character:U+010000 〜 U+10FFFF,UTF-16 においてサロゲート・ペアで表される,俗に言うサロゲート(ペア)文字 (誤称)) をシフトJISに変換したいということなんだろうけど, そんな文字は Shift_JIS (標準的なシフトJIS) や Windows-31J (Windows 版シフトJIS,別名 CP932) には一文字も含まれていない. したがってこの意味でもシフトJISと「サロゲート」は関係ないし,もちろん変換もできない.
2015/07/31(金) 追記・改訂
ただし「シフトJIS」の文字の中でも次のものは Unicode の補助文字に対応する.
2013/04/17(水) 追記
以前からこれらの検索ワードが多いので, 「なんでこんなにシフトJISとサロゲートが変換できると思い込んでいる (らしい) 人が多いんだろう?」とずっと不思議に思っていた. ところが今日,「機種依存文字 環境依存文字 サロゲート …」で検索してきた人と,「髙(はしごだか) サロゲート」で検索して来た人がいた.
そうか,謎はすべて解けた!
Unicode のサロゲートはシフトJISの機種依存文字 (Windows-31J の独自拡張部分)
に対応するものだとこっぴどく勘違いしているのか!
しかしここで新たな謎が….なんでそういう誤解をしたんだろう?
誤解の発生過程を憶測してみる.
UTF-8 の4バイト文字は補助文字 (俗称・誤称:サロゲート文字)
だってことは理解してますか?
上に書いたとおりShift_JIS (標準的なシフト JIS) や
Windows-31J/CP932 (Windows 版シフト JIS) には Unicode
の補助文字に対応する文字は一つもないから変換できないと何度言えば(ry
2015/07/31(金) 追記
携帯電話の絵文字や Shift_JIS-2004 の一部の漢字は Unicode の補助文字に対応する.
Unicode (12.1.0) 約14万文字の中で
Shift_JIS に変換できるのはわずか 5% に過ぎませんよ.
全部知りたいんですか?
変換できない文字の一覧を検索して来る人も多いけど,そんなもの
(ほとんど絶対) 誰も作っていないと思う.
(変換できる文字より変換できない文字の方がはるかに多いので,
そんな表を作るのはアホらしい.)
書きかけです.
準備中
dwFlags=MB_ERR_INALID_CHARS の場合
dwFlags=0 の場合
全般的なまとめについては準備中. 個別の2バイト文字の変換結果については, 「Windows-31J (CP932) 文字コード表」 (Windows-31J のすべての2バイト文字を MultiByteToWideChar() で変換したファイル (UTF-8/16BE)) を参照.
実験準備中.
対象文字コード:
とりあえず関連リンク.
Unicode 1文字を16ビットで表す. ただし第1〜16面 (U+010000 〜 U+10FFFF) の文字にはサロゲート・ペアを使用する.
サロゲート・ペアは本来 UTF-16 のものであり,それ以外では (UTF-16 をベースにした) UTF-7,そして残念ながら混乱の元となる CESU-8 でのみ用いられる (はず).
サロゲート・ペア内での UTF-16 符号単位の順序は (上位,下位) の順.
2013/08/10(土)
サロゲート(ペア)を壊滅的に理解できていない (どころか独創的に誤解している)
人があまりにも多いようなので追記.
(Unicode 以前からシフト JIS や EUC-*
などのマルチバイト文字列を (ライブラリに頼らず自力で)
処理してきたプログラマにとっては,サロゲートも本質的に同じなので朝飯前のはず.
(符号単位が1バイトから2バイトに変わっただけ.))
Unicode スカラ値 (実質21bit) | UTF-16 符号単位 | |
---|---|---|
BMP文字 (0面:U+0000 〜 U+FFFF) |
┏━━━┯━━━━━━━━━━┓ ┃0 0000│xxxx xxxx xxxx xxxx┃… スカラ値 ┗━━━┷━━━━━━━━━━┛ ├- 面 -┼--- 区 --┼--- 点 --┤ (5bit) (8bit) (8bit) |
┏━━━━━━━━━━┓ ┃xxxx xxxx xxxx xxxx ┃ ┗━━━━━━━━━━┛ |
補助文字 (1面〜16面: U+10000 〜 U+10FFFF) |
w wwww xxxx xxyy yyyy yyyy … スカラ値 -) 0 0001 0000 0000 0000 0000 … 補助面の最初の ─────────────── 文字のスカラ値 0 zzzz xxxx xxyy yyyy yyyy … 補助面内での連番 (実質20bit) (面番号:wwwww=00001〜10000) |
サロゲートペア ┏━━━━━━━━━━┓ ┃1101 10zz zzxx xxxx ┃… 上位サロゲート符号単位 ┗━━━━━━━━━━┛ (U+D800 〜 U+DBFF) ┏━━━━━━━━━━┓ ┃1101 11yy yyyy yyyy ┃… 下位サロゲート符号単位 ┗━━━━━━━━━━┛ (U+DC00 〜 U+DFFF) |
Surrogate Character.
A misnomer. It would be an encoded character having a surrogate code point, which is impossible. Do not use this term.訳:
サロゲート文字
誤称.サロゲート符号位置を持つ文字ということになるが,これはありえない. この誤称を使うな!
「UTF-8 サロゲート(ペア)」で検索して来る人が多いけど,
サロゲートペアは補助文字を UTF-16
で表現したものであって,UTF-8 では使いません!(禁止されています!)
UTF-8 で扱うのは補助文字であって,サロゲート(ペア)ではありません.
MySQL の UTF-8 も3バイト文字までしか対応していないらしい. つまり事実上 CESU-8 である.(2007/03/26 時点)
Unicode スカラ値 (実質21bit) |
UTF-8 符号単位 | |||
---|---|---|---|---|
第1バイト | 第2バイト | 第3バイト | 第4バイト | |
UTF8-1 0面0区0〜127点 (ASCII) U+0000 〜 U+007F (0000 0000 0xxx xxxx) 面 区 点 ├ 5bit ┼- 8bit -┼- 8bit -┤ ┏━━━┯━━━━┯━━━━┓ ┃ 00000 00000000 0xxxxxxx┃ ┗━━━┷━━━━┷━━━━┛ ├-7bit-┤ ASCII |
0xxx xxxx (0x00〜0x7F) (ASCII) |
- | - | - |
UTF8-2 0面0区128点〜7区 U+0080 〜 U+07FF (0000 0xxx xxyy yyyy) ┏━━━━━━━━━━━━┓ ┃00000 00000 xxxxx yyyyyy┃ ┗━━━━━━━━━━━━┛ │ 10bit │ 5bit| 6bit │ |
110x xxxx (0xC2〜0xDF) |
10yy yyyy (0x80〜0xBF) |
- | - |
UTF8-3 0面8〜255区 U+0800 〜 U+D7FF U+E000 〜 U+FFFF (xxxx yyyy yyzz zzzz) Surrogate 領域 (U+D800 〜 U+DFFF) は使用禁止 ┏━━━━━━━━━━━━┓ ┃00000 xxxx yyyyyy zzzzzz┃ ┗━━━━━━━━━━━━┛ │ 5bit|4bit| 6bit | 6bit │ |
1110 xxxx | 10yy yyyy | 10zz zzzz (0x80〜0xBF) |
- |
(0xE0) | (0xA0〜0xBF) | |||
(0xE1〜0xEC) | (0x80〜0xBF) | |||
(0xED) | (0x80〜0x9F) | |||
(0xEE〜0xEF) | (0x80〜0xBF) | |||
UTF8-4 1〜16面 (補助文字) U+010000 〜 U+10FFFF (x xxyy yyyy zzzz zzww wwww) ┏━━━━━━━━━━━━┓ ┃xxx yyyyyy zzzzzz wwwwww┃ ┗━━━━━━━━━━━━┛ │3bit| 6bit| 6bit | 6bit │ |
1111 0xxx | 10yy yyyy | 10zz zzzz (0x80〜0xBF) |
10ww wwww (0x80〜0xBF) |
(0xF0) | (0x90〜0xBF) | |||
(0xF1〜0xF3) | (0x80〜0xBF) | |||
(0xF4) | (0x80〜0x8F) |
■注意
Surrogate Character.
A misnomer. It would be an encoded character having a surrogate code point, which is impossible. Do not use this term.
RFC2279 は廃止されたが,次の理由でここに掲載する.
UCS-4 | 第1バイト | 第2バイト | 第3バイト | 第4バイト | 第5バイト | 第6バイト |
---|---|---|---|---|---|---|
0群0面0区0〜127点 (ASCII) 0000 0000 0xxx xxxx (U+0000 〜 U+007F) |
0xxx xxxx (0x00〜0x7F) |
- | - | - | - | - |
0群0面0区128点〜7区 0000 0xxx xxyy yyyy (U+0080 〜 U+07FF) |
110x xxxx (0xC0〜0xDF) |
10yy yyyy (0x80〜0xBF) |
- | - | - | - |
0群0面8〜255区 xxxx yyyy yyzz zzzz (U+0800 〜 U+FFFF) |
1110 xxxx (0xE0〜0xEF) |
10yy yyyy (0x80〜0xBF) |
10zz zzzz (0x80〜0xBF) |
- | - | - |
0群1〜31面 0000 0000 000x xxyy yyyy zzzz zzww wwww |
1111 0xxx (0xF0〜0xF7) |
10yy yyyy (0x80〜0xBF) |
10zz zzzz (0x80〜0xBF) |
10ww wwww (0x80〜0xBF) |
- | - |
0群32面〜3群 0000 00xx yyyy yyzz zzzz wwww wwvv vvvv |
1111 10xx (0xF8〜0xFB) |
10yy yyyy (0x80〜0xBF) |
10zz zzzz (0x80〜0xBF) |
10ww wwww (0x80〜0xBF) |
10vv vvvv (0x80〜0xBF) |
- |
4群〜127群 0xyy yyyy zzzz zzww wwww vvvv vvuu uuuu |
1111 110x (0xFC〜0xFD) |
10yy yyyy (0x80〜0xBF) |
10zz zzzz (0x80〜0xBF) |
10ww wwww (0x80〜0xBF) |
10vv vvvv (0x80〜0xBF) |
10uu uuuu (0x80〜0xBF) |
実験中なので,仕様は予告なく変更する可能性があります.
#include <assert.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <wchar.h> #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) // C99 以後 #include <stdint.h> #elif defined(__unix__) #include <sys/types.h> #else // 処理系に応じて変更すること. typedef unsigned char uint8_t; // 8ビット無符号整数 typedef unsigned short uint16_t; // 16ビット無符号整数 typedef unsigned int uint32_t; // 32ビット無符号整数 #endif typedef uint8_t utf8_t; // UTF-8 の符号単位 typedef uint16_t utf16_t; // UTF-16 の符号単位 typedef uint32_t utf32_t; // UTF-32 の符号単位 typedef uint32_t unicode_t; // Unicode スカラ値 typedef uint32_t ucs4_t; // UCS-4 の1文字 typedef int Bool; #define OK 0 #define FAIL (-1) // Unicode スカラ値の範囲 #define UNICODE_MIN ((unicode_t)0x000000) #define UNICODE_MAX ((unicode_t)0x10FFFF) // 無効な Unicode スカラ値 // (注意:規格とは無関係に,このページで独自に定義した値.) #define UNICODE_EOF (~(unicode_t)0) // 補助面の最初の符号位置 (1面の最初の符号位置) #define UNICODE_PLANE1_MIN ((unicode_t)0x010000) // UTF-16 符号単位の範囲 #define UTF16_MIN ((utf16_t)UNICODE_MIN) #define UTF16_MAX ((utf16_t)0xFFFF) // UCS-4 の範囲 #define UCS4_MIN ((ucs4_t)0x00000000) #define UCS4_MAX ((ucs4_t)0x7FFFFFFF) /*───────────────────────────────────── 説明 :サロゲート領域の定義. 2007/08/12(日) 作成 2007/10/20(土) SURROGATE_BITS,{HIGH,LOW,BOTH}_SURROGATE_MASK を追加. ─────────────────────────────────────*/ #define HIGH_SURROGATE_MIN ((utf16_t)0xD800) // 上位サロゲート領域開始位置 #define HIGH_SURROGATE_MAX ((utf16_t)0xDBFF) // 上位サロゲート領域終了位置 #define LOW_SURROGATE_MIN ((utf16_t)0xDC00) // 下位サロゲート領域開始位置 #define LOW_SURROGATE_MAX ((utf16_t)0xDFFF) // 下位サロゲート領域終了位置 #define SURROGATE_MIN HIGH_SURROGATE_MIN // サロゲート領域開始位置 #define SURROGATE_MAX LOW_SURROGATE_MAX // サロゲート領域終了位置 // サロゲート可変部分のビット数 (上位,下位共通) #define SURROGATE_BITS 10 // サロゲート符号単位の可変部分を抽出するためのマスク #define HIGH_SURROGATE_MASK (((utf16_t)1 << SURROGATE_BITS) - 1) // 上位用 #define LOW_SURROGATE_MASK (((utf16_t)1 << SURROGATE_BITS) - 1) // 下位用 #define BOTH_SURROGATE_MASK (((utf16_t)1 << (SURROGATE_BITS + 1)) - 1) // 上下用 /*───────────────────────────────────── 機能 :有効なスカラ値か否かを判定する. 入力 :unicode:スカラ値. 戻り値:unicode が有効なスカラ値のときそのときに限り真. 2009/01/23(金) 作成 ─────────────────────────────────────*/ #define IsValidUnicode(unicode) \ (((unicode) <= UNICODE_MAX) && !IsSurrogate(unicode)) /*───────────────────────────────────── 機能 :UTF-16 の符号単位が上位サロゲートか否かを判定する. 入力 :utf16:UTF-16 の符号単位. 戻り値:utf16 が上位サロゲートのときそのときに限り真. 2007/08/12(日) 作成 2007/10/20(土) 改定 ─────────────────────────────────────*/ #define IsHighSurrogate(utf16) \ (((unicode_t)(utf16) & ~(unicode_t)HIGH_SURROGATE_MASK) \ == (unicode_t)HIGH_SURROGATE_MIN) /*───────────────────────────────────── 機能 :UTF-16 の符号単位が下位サロゲートか否かを判定する. 入力 :utf16:UTF-16 の符号単位. 戻り値:utf16 が下位サロゲートのときそのときに限り真. 2007/08/12(日) 作成 2007/10/20(土) 改定 ─────────────────────────────────────*/ #define IsLowSurrogate(utf16) \ (((unicode_t)(utf16) & ~(unicode_t)LOW_SURROGATE_MASK) \ == (unicode_t)LOW_SURROGATE_MIN) /*───────────────────────────────────── 機能 :UTF-16 の符号単位が上位または下位サロゲートか否かを判定する. 入力 :utf16:UTF-16 の符号単位. 戻り値:utf16 が上位または下位サロゲートのときそのときに限り真. 2007/08/12(日) 作成 2007/10/20(土) 改定 ─────────────────────────────────────*/ #define IsSurrogate(utf16) \ (((unicode_t)(utf16) & ~(unicode_t)BOTH_SURROGATE_MASK) \ == (unicode_t)SURROGATE_MIN) /*───────────────────────────────────── 機能 :UTF-16 の2つの符号単位の組 (first,second) がサロゲート・ペアか否か を判定する. 入力 :first,second:UTF-16 の符号単位.first が先,second が後. 戻り値:(first,second) がサロゲート・ペアのときそのときに限り真. 2007/08/12(日) 作成 ─────────────────────────────────────*/ #define IsSurrogatePair(first, second) \ (IsHighSurrogate(first) && IsLowSurrogate(second)) /*───────────────────────────────────── 機能 :IsHighSurrogate(),IsLowSurrogate(),IsSurrogate() のテスト. すべての UTF-16 符号単位についてこれらの述語の判定結果が正しいことを 確認するとともに,真理値表を out に出力する. 2007/08/12(日) 作成 2007/08/16(木) 改名 (SurrogateTest() ⇒ IsSurrogateTest()) 2007/10/20(土) 改定 ─────────────────────────────────────*/ void IsSurrogateTest(FILE *out) { unicode_t c; Bool isHighSurrogate, isLowSurrogate, isSurrogate; fprintf(out, "UTF-16\tHigh\tLow\tSurrogate\n"); for(c = UTF16_MIN; c <= UTF16_MAX; c++) { // Is{High,Low,}Surrogate() と別の方法で判定する. isHighSurrogate = ValueInRangeInclusive(HIGH_SURROGATE_MIN, c, HIGH_SURROGATE_MAX); isLowSurrogate = ValueInRangeInclusive(LOW_SURROGATE_MIN, c, LOW_SURROGATE_MAX); isSurrogate = ValueInRangeInclusive(SURROGATE_MIN, c, SURROGATE_MAX); // 異なる判定方法の結果が一致することを確認する. assert(IsHighSurrogate(c) == isHighSurrogate); assert(IsLowSurrogate(c) == isLowSurrogate); assert(IsSurrogate(c) == isSurrogate); // 判定結果 (真理値表) を出力する. fprintf(out, "%04X\t%s\t%s\t%s\n", c, isHighSurrogate ? "*" : "", isLowSurrogate ? "*" : "", isSurrogate ? "*" : ""); } } /*───────────────────────────────────── テスト用 ─────────────────────────────────────*/ int main(void) { IsSurrogateTest(stdout); return EXIT_SUCCESS; }
/*───────────────────────────────────── 機能 :サロゲート・ペアを解読 (Unicode スカラ値に変換) する. 入力 :(1) high:上位サロゲート符号単位 (0xD800 〜 0xDBFF). (2) low :下位サロゲート符号単位 (0xDC00 〜 0xDFFF). 戻り値:サロゲート・ペアに対応する Unicode スカラ値 (U+010000 〜 U+10FFFF). 2007/08/12(日) 作成 2007/10/20(土) 改定 2008/06/24(火) 改定 ─────────────────────────────────────*/ unicode_t DecodeSurrogatePair(unicode_t high, unicode_t low) { return ((high & (unicode_t)HIGH_SURROGATE_MASK) << SURROGATE_BITS) + (low & (unicode_t)LOW_SURROGATE_MASK) + UNICODE_PLANE1_MIN; } /*───────────────────────────────────── 機能 :Unicode スカラ値 (1〜16面) を上位サロゲートに変換する. 入力 :unicode:Unicode スカラ値.1〜16面 (U+010000 〜 U+10FFFF) でなければ ならない. 戻り値:unicode に対応する上位サロゲート. 2007/08/16(木) 作成 2007/10/20(土) 改定 2008/06/24(火) 改定 ─────────────────────────────────────*/ #define Unicode_ToHighSurrogate(unicode) \ ((utf16_t)(((((unicode) - UNICODE_PLANE1_MIN) >> SURROGATE_BITS) \ & HIGH_SURROGATE_MASK) | HIGH_SURROGATE_MIN)) /*───────────────────────────────────── 機能 :Unicode スカラ値 (1〜16面) を下位サロゲートに変換する. 入力 :unicode:Unicode スカラ値.1〜16面 (U+010000 〜 U+10FFFF) でなければ ならない. 戻り値:unicode に対応する下位サロゲート. 2007/08/16(木) 作成 2007/08/28(火) 改定 (無駄を省いて簡略化) 2007/10/20(土) 改定 ─────────────────────────────────────*/ #define Unicode_ToLowSurrogate(unicode) \ ((utf16_t)((unicode) & LOW_SURROGATE_MASK | LOW_SURROGATE_MIN)) /*───────────────────────────────────── 機能 :Unicode_ToHighSurrogate(),Unicode_ToLowSurrogate(), DecodeSurrogatePair() のテスト. ・すべてのサロゲート・ペアについて,DecodeSurrogatePair(), Unicode_To{High,Low}Surrogate() の結果が正しいことを確認する. ・サロゲート・ペアと Unicode スカラ値の対応表を out に出力する. 2007/08/12(日) 作成 (DecodeSurrogatePair() のテスト.) 2007/08/16(木) Unicode_To{High,Low}Surrogate() のテストを追加. 2007/08/18(土) 改名 (DecodeSurrogatePairTest() ⇒ SurrogatePairConvTest()) 2007/10/20(土) 改定 2008/06/24(火) 改定 ─────────────────────────────────────*/ void SurrogatePairConvTest(FILE *out) { unicode_t high, low; // サロゲート・ペア unicode_t high2, low2; // Unicode_To{High,Low}Surrogate() の結果. unicode_t value; // DecodeSurrogatePair() の変換結果 // 第1〜16面の符号位置を順番に. unicode_t refval = UNICODE_PLANE1_MIN; fprintf(out, "High Low Unicode\n" "---- ---- --------\n"); for(high = HIGH_SURROGATE_MIN; high <= HIGH_SURROGATE_MAX; high++) { for(low = LOW_SURROGATE_MIN; low <= LOW_SURROGATE_MAX; low++, refval++) { assert(IsSurrogatePair(high, low)); value = DecodeSurrogatePair(high, low); high2 = Unicode_ToHighSurrogate(value); low2 = Unicode_ToLowSurrogate(value); fprintf(out, "%04X %04X U+%06lX\n", high, low, value); assert(value == refval); assert(high2 == high); assert(low2 == low); } } assert(refval == UNICODE_MAX + 1); } /*───────────────────────────────────── テスト用 ─────────────────────────────────────*/ int main(void) { SurrogatePairConvTest(stdout); return EXIT_SUCCESS; }
/*───────────────────────────────────── 機能 :Unicode スカラ値 ⇒ UTF-16 変換 (UTF-16 文字列バッファに1文字追記). Unicode スカラ値 unicode を UTF-16 文字列バッファに追記する. 入出力:*pWritePtr:UTF-16 文字列バッファの,次の書き込み位置を指すポインタ. 書き込み成功ならば,次の書き込み位置を指すように更新される. 入力 :(1) bufEnd:UTF-16 文字列バッファの直後のアドレス.つまり UTF-16 バ ッファ がN要素の配列 buf[N] ならば &buf[N].ただし UTF-16 文字 列を必ず NUL 終端したい場合は &buf[N-1] とする (NUL は自分で書き 込むこと). (2) unicode:Unicode スカラ値. 戻り値:UTF-16 バッファに書き込まれた UTF-16 符号単位の数 (1〜2). バッファの空き容量不足で書き込めなかった場合には0. unicode が範囲外 (>U+10FFFF) の場合は -1. 2007/08/16(木) 作成 2007/10/20(土) 改定 ─────────────────────────────────────*/ int UTF16_PutChar(utf16_t **pWritePtr, utf16_t *bufEnd, unicode_t unicode) { utf16_t *dest = *pWritePtr; // 書き込み位置 if(unicode <= UTF16_MAX) { // unicode が0面の場合:そのまま書き込む. if(dest >= bufEnd) goto BufferFull; *dest = (utf16_t)unicode; *pWritePtr = dest + 1; // 次の書き込み位置 return 1; } else if(unicode <= UNICODE_MAX) { // unicode が1〜16面の場合:サロゲート・ペアに変換して書き込む. if(dest + 1 >= bufEnd) goto BufferFull; dest[0] = Unicode_ToHighSurrogate(unicode); dest[1] = Unicode_ToLowSurrogate(unicode); *pWritePtr = dest + 2; // 次の書き込み位置 return 2; } else { // unicode が17面以上の場合:エラー. return -1; } BufferFull: return 0; } /*───────────────────────────────────── 機能 :UTF-16 ⇒ Unicode スカラ値変換 UTF-16 文字列から1文字読み取り,Unicode スカラ値に変換する. 文字列は NUL 終端でも,そうでなくてもよい. 入力 :stringEnd:UTF-16 文字列の終端を指定する. (1) 非 NUL 終端文字列の場合:文字列の直後 (最後の符号単位の次のアド レス) を指す. (2) NUL 終端文字列の場合:NULL. 入出力:*pReadPtr:UTF-16 文字列の読み出し位置を指すポインタ.1文字を読み 出した後,次の読み出し位置に更新される.ただし文字列が NUL 終端 (stringEnd=NULL) で,既に NUL を指している場合には更新されない. 戻り値:*pReadPtr が指す1文字.ただし, ・NUL 終端文字列で,*pReadPtr が終端 NUL を指している場合は NUL を 返し,読み出し位置は更新しない. ・非 NUL 終端文字列 (stringEnd≠NULL) で,既に終端に達している場合 (*pReadPtr≧stringEnd) は UNICODE_EOF を返し,読み出し位置は更新 しない. ・**pReadPtr が孤立した ((正しい) ペアでない) サロゲートの場合は, それをそのまま返す.読み出し位置は次の符号単位に進む. 2007/08/17(金) 作成 ─────────────────────────────────────*/ unicode_t UTF16_GetChar(const utf16_t **pReadPtr, const utf16_t *stringEnd) { const utf16_t *src = *pReadPtr; unicode_t uc, uc2; if(stringEnd == NULL) { // NUL 終端文字列の場合 if((uc = *src++) != 0) { if(IsHighSurrogate(uc)) { uc2 = *src; if(IsLowSurrogate(uc2)) { uc = DecodeSurrogatePair(uc, uc2); src++; } } *pReadPtr = src; } } else { // 非 NUL 終端文字列の場合 if(src >= stringEnd) { uc = UNICODE_EOF; // 文字列終端 } else { uc = *src++; if(IsHighSurrogate(uc) && (src < stringEnd)) { uc2 = *src; if(IsLowSurrogate(uc2)) { uc = DecodeSurrogatePair(uc, uc2); src++; } } *pReadPtr = src; } } return uc; } /*───────────────────────────────────── 機能 :UTF-16 文字列の長さ (文字数および符号単位数) を取得する. 入力 :(1) string:UTF-16 文字列.NUL 終端でも,そうでなくてもよい. (2) stringEnd:string の終端. ・非 NUL 終端文字列の場合:string の最後の符号単位の次のアドレス. ・NUL 終端文字列の場合:NULL. 出力 :*pNUnits:pNUnits≠NULL ならば,string の UTF-16 符号単位の個数を返す. 終端 NUL は含まない. 戻り値:string に含まれる文字数.ペアをなさないサロゲートも1文字と数える. (UTF16_GetChar() が返す文字 (終端 NUL を除く) の個数と一致.) 2007/08/18(土) 作成 ─────────────────────────────────────*/ size_t UTF16_Length(const utf16_t *string, const utf16_t *stringEnd, size_t *pNUnits) { const utf16_t *p = string; size_t nChars = 0; unicode_t uc; if(stringEnd == NULL) { // NUL 終端文字列の場合 while((uc = *p) != 0) { p++; nChars++; if(IsHighSurrogate(uc) && IsLowSurrogate(*p)) p++; } } else { // 非 NUL 終端文字列の場合 while(p < stringEnd) { nChars++; uc = *p++; if(IsHighSurrogate(uc) && (p < stringEnd) && IsLowSurrogate(*p)) p++; } } if(pNUnits != NULL) *pNUnits = (size_t)(p - string); return nChars; } /*───────────────────────────────────── 機能 :UTF16_GetChar(),UTF16_PutChar(),UTF16_Length() のテスト. エラー処理は手抜き. (1) UTF-16 文字列 string を NUL 終端文字列として buf[] にコピーする (Unicode スカラ値経由) とともに,文字数および UTF-16 符号単位数 を数える. (2) UTF-16 文字列 string を非 NUL 終端文字列として buf[] にコピーす る (Unicode スカラ値経由) とともに,文字数および UTF-16 符号単位 数を数える.また UTF-32 ファイル UTF-32.txt に書き出す. (3) buf[] を UTF-16 ファイル UTF-16.txt に書き出す. 2007/08/18(土) 作成 ─────────────────────────────────────*/ void UTF16_Test(void) { // Windows では wchar_t=UTF-16 なので OK だが,他の OS ではダメかも. static const utf16_t string[] = L"\xFEFF" // BOM L"\x24B6牛丼一筋80年♪ \xD842\xDFB7野家\n" // サロゲート・ペア ([土]+[口]) L"\x24B7森\x9DD7外\n" // Windows-31J に存在しない文字 // [區鳥] L"\x24B8草\x5F45剛\n" // Windows-31J 機種依存文字 // [弓剪] L"\x24B9\x9AD9知新聞\n" // Windows-31J 機種依存文字 // (はしご高) L"\x24BA虹は♂,\x873Aは♀.\n" // Windows-31J に存在しない文字 // [虫兒] L"\x2707\x21D6\x21D7\x21D8\x21D9\n"; // Unicode 記号 utf16_t buf[64]; const utf16_t *src = string; const utf16_t * const stringEnd = string + wcslen(string); utf16_t *dest = buf; utf16_t * const bufEnd = ArrayEnd(buf); unicode_t uc; size_t size, nChars, nUnits; int result; FILE *out; // NUL 終端文字列としてコピーしてみる. for(nChars = 0; ; nChars++) { uc = UTF16_GetChar(&src, NULL); result = UTF16_PutChar(&dest, bufEnd, uc); printf("%06X %d\n", uc, result); if((uc == 0) || (result <= 0)) break; } if(result > 0) { assert(wcscmp(string, buf) == 0); assert(nChars == UTF16_Length(string, NULL, &nUnits)); assert(nUnits == wcslen(string)); printf("%lu characters, %lu units\n", (unsigned long)nChars, (unsigned long)nUnits); } printf("\n"); // 非 NUL 終端文字列としてコピーしてみる. // UTF-32 のファイルも作ってみる. out = fopen("UTF-32.txt", "wb"); assert(out != NULL); src = string; dest = buf; nChars = 0; while((uc = UTF16_GetChar(&src, stringEnd)) != UNICODE_EOF) { result = UTF16_PutChar(&dest, bufEnd, uc); printf("%06X %d\n", uc, result); if(result <= 0) break; size = fwrite(&uc, 1, sizeof(uc), out); assert(size == sizeof(uc)); nChars++; } fclose(out); if(result > 0) { assert(memcmp(string, buf, sizeof(utf16_t) * (size_t)(dest - buf)) == 0); assert(nChars == UTF16_Length(string, stringEnd, &nUnits)); assert(nUnits == (size_t)(src - string)); printf("%lu characters, %lu units\n", (unsigned long)nChars, (unsigned long)nUnits); } // UTF-16 のファイルも作ってみる. out = fopen("UTF-16.txt", "wb"); assert(out != NULL); size = fwrite(buf, sizeof(buf[0]), (size_t)(dest - buf), out); assert(size == (size_t)(dest - buf)); fclose(out); } /*───────────────────────────────────── テスト用. ─────────────────────────────────────*/ int main(void) { UTF16_Test(); return EXIT_SUCCESS; }
// UTF-8/CESU-8 1文字の最大バイト数 #define UTF8_RFC3629_MAXBYTES 4 #define UTF8_RFC2279_MAXBYTES 6 #define UTF8_MAXBYTES UTF8_RFC3629_MAXBYTES #define CESU8_MAXBYTES 6 /*───────────────────────────────────── 入力 :n:1 〜 UTF8_RFC2279_MAXBYTES. 戻り値:UTF-8 のnバイト文字に含まれるスカラ値のビット数. 2008/12/28(日) 作成 ─────────────────────────────────────*/ #define UTF8_BITS(n) (((n) == 1) ? 7 : (n) * 5 + 1) /*───────────────────────────────────── 入力 :n:1 〜 UTF8_RFC2279_MAXBYTES. 戻り値:UTF-8 でnバイト文字として表現可能な最大の Unicode スカラ値. 注意 :n=RFC3629_MAXBYTES の場合,0x10FFFF (RFC3629 での最大値) ではなく, 0x1FFFFF (RFC2279 での最大値) を返す. 用途 :UTF-8 非最短形式の効率的判定. 2008/12/28(日) 作成 ─────────────────────────────────────*/ #define UTF8_MAX(n) ((unicode_t)(((unicode_t)1 << UTF8_BITS(n)) - 1U)) /*───────────────────────────────────── 入力 :byte:UTF-8 文字列内の1バイト (無符号整数型). 戻り値:byte が UTF-8 のnバイト文字 (UTF8-n) の先頭バイトのときそのときに 限り,IS_UTF8_<n>(byte) は真を返す. 注意 :非最短形式の先頭バイト値 (0xC0〜0xC1,0xF5〜0xF7) を排除していない. 余談 :IS_UTF8_[2-6]() については,ValueInRangeInclusive(0xC0, (byte), 0xDF) などとするのに比べて条件分岐が1回少ないのでちょっと速い(はず). 2009/02/10(火) 作成 ─────────────────────────────────────*/ #define IS_UTF8_1(byte) ((byte) <= 0x7FU) #define IS_UTF8_2(byte) (((byte) & 0xE0U) == 0xC0U) #define IS_UTF8_3(byte) (((byte) & 0xF0U) == 0xE0U) #define IS_UTF8_4(byte) (((byte) & 0xF8U) == 0xF0U) #define IS_UTF8_5(byte) (((byte) & 0xFCU) == 0xF8U) // RFC2279 のみ #define IS_UTF8_6(byte) (((byte) & 0xFEU) == 0xFCU) // RFC2279 のみ /*───────────────────────────────────── 入力 :byte:UTF-8 文字列内の1バイト (無符号整数型). 戻り値:byte が UTF-8 の複数バイト文字の第2バイト以後 (UTF8-tail) のとき そのときに限り真. 2009/02/10(火) 作成 ─────────────────────────────────────*/ #define IS_UTF8_TAIL(byte) (((byte) & 0xC0U) == 0x80U) /*───────────────────────────────────── 入力 :byte:UTF-8 文字列内の1バイト (無符号整数型). 戻り値:byte が UTF-8 の先頭バイトのときそのときに限り真. 注意 :非最短形式の先頭バイト値 (0xC0〜0xC1,0xF5〜0xF7) を排除していない. 2009/02/10(火) 作成 2010/03/18(木) 高速化のため判定順序を入れ替え. ─────────────────────────────────────*/ #define IS_UTF8_RFC3629_HEAD(byte) \ (!IS_UTF8_TAIL(byte) && ((byte) <= 0xF7U)) #define IS_UTF8_RFC2279_HEAD(byte) \ (!IS_UTF8_TAIL(byte) && ((byte) <= 0xFDU)) #define IS_UTF8_HEAD(byte) IS_UTF8_RFC3629_HEAD(byte)
「サロゲート(ペア)文字」(誤称・俗称)
じゃなくて「補助文字 (supplementary character)」ね.
↓この表の1177ページ "Linear B Syllabary"
(線文字B) 以後全部がそれです.
(まさか漢字だけだと思ってないよね?)
http://www.unicode.org/Public/UCD/latest/charts/CodeCharts.pdf
Unicode (最新版) 全文字一覧 (PDF,注意:約100MB)
(補助文字のスカラ値の範囲は U+010000 〜 U+10FFFF.)
あのー,UTF-8 がどういう性格の文字コード (符号化方式) か,ちょっとでも調べてみたことありますか?
UTF-8 は ASCII の完全上位互換になるように決められた符号化方式なので,
つまり変換する必要がないか,変換できないのどちらかしかないから, 「変換方法」を探しても見つかるわけがない.
闇雲に「変換方法」を探す前に, どういう文字コードなのかを少しは理解していないと,象の卵 (あるはずのないもの) をいつまでも探し続けるはめになりますよ.
時々こういうキーワードで検索して来る人がいるが, 文字コードの規格で終端文字というものが決まっているわけではない. 「終端文字として何を使うか」ではなく,「終端文字というものを使う」ことさえ規定されていない. テキストファイルに終端文字なんてないでしょ? えっ,それも知らないの? そういう人は, 時々テキストファイルをバイナリエディタで開いて見る習慣をつけると文字コードや文字列の正体が理解しやすくなると思うよ.
0 (NUL) をメモリ内の文字列の終端文字として使用するのはC言語 (およびその派生言語) の仕様. C言語が普及する以前は,終端文字というものを使わない文字列の方が主流だった.
正確に言うと,C言語であっても,すべての文字列が NUL 終端とは限らない.
文字列の 終端方法
(と書くと文字列には必ず終端文字があると誤解する人がいそうだから
「長さの定義方法」に訂正)
は API やライブラリの仕様なので,
それぞれのマニュアルでちゃんと確認すること.
API によっては,終端文字のない文字列を使用する.
例えば Windows の文字コード変換 API である
MultiByteToWideChar( ) や
WideCharToMultiByte( ) などは,文字列は NUL
終端でもそうでなくても使用できる.一般論で「(エンコーディング名)
終端文字」なんて検索しても正解が見つかるわけがない.
ところで文字列 (の本体) は「符号単位の配列」だということは理解してる?
「文字列には必ず終端文字がある」という固定観念に凝り固まっている人は,配列の使い方を勉強し直した方がいい.
配列の長さ (要素数) を指定・取得するにはどんな方法があると思う?
(ASCII などの1バイト文字列やマルチバイト文字列 (シフトJIS,EUC-*,UTF-8 など)
の符号単位は1バイトだが,UTF-16 は2バイト,UTF-32 では4バイト.
もちろん NUL も一つの符号単位で表されるので,1バイトとは限らない.)
■余談
NUL 終端文字列 (NUL-terminated string) は「C文字列 (C string)」,「ASCIZ (または ASCIIZ) 文字列」(ASCII+Zero の略) などともいう.
Wikipedia 英語版の "Null-terminated string" によると,C言語が登場するより前に NUL 終端文字列を使っていたのは PDP-10 (1966年生産開始(?)の36ビットメインフレーム) と PDP-11 (1970年出荷開始の16ビットミニコン) のアセンブリ言語らしい.
当時は現在に比べて桁違いにメモリ容量が少なく高価だったので, メモリ使用量を節約しつつ任意の長さの文字列を扱えるように NUL 終端文字列が考案されたようである. (ただし長い文字列の長さを調べるのに時間がかかる.)
CP/M およびそれを真似た DOS では,文字列を出力する (アセンブラ)
API (INT 21H,AH=09H) に渡す文字列は '$' 終端文字列だった.
米国製 OS だというのに,これじゃ金額を出力できないじゃないか.
ひどすぎる仕様だ.(笑)
(実際には,文字列は別の API で出力していたと思う.)
ASCII 制御文字には ETX (End Of Text:テキスト終了,0x03) というのがあるが, これは伝送制御文字なので,装置間の通信メッセージでしか用いられないし, 必ず使用しなければならないというものでもない (プロトコルに依存する).
ETX は CTRL-C のことだが,ASCII 本来の意味は現在の PC での用法とは全く関係ない. これに対し UNIX/Linux では,コンソールからの入力を終了させる EOF 文字として CTRL-D が用いられているが,これは EOT (End Of Transmission:伝送終了,0x04) なので ASCII 本来の使い方である. (UNIX 開発当時,コンピュータと端末は別々の装置だった.)
■参考
なぜか最近,こういうキーワードで検索して来る人が多い気がする.
以前は気になるほど多くなかったと思うんだけど.
どうやら EOF が文字コードだと思っている人が増えたらしい.
念のために聞くけど,"EOF" の意味は知ってますよね?
End-Of-File … ファイルを読もうとしても,既にファイルの最後まで読んでしまっているので, それ以上読み取れるデータがない状態.じゃあ質問するけど,
どれも難しい問題に思う人がいるかもしれないが,こういう問題は存在しない. なぜなら,EOF は文字コードとは全く無関係だから.EOF は文字列や文字コードの概念ではなく,ファイルシステム API (ファイル入出力関数) の概念なので,EOF の判定方法についてはそれらのマニュアルをちゃんと読むこと. 例えばC標準ライブラリ関数 fgetc() などが返す EOF という値はエラー値であって文字コードではない. (EOF の具体的な値を知りたければ自分で stdio.h を見て確認すること. 文字コードでは絶対あり得ない値であることがわかるだろう.)
「そんなこと言うけど,EOF 文字 (0x1A=CTRL-Z) というものが実際にあるじゃないか」と言いたい人もいるだろう. 確かにそうだけど,これははっきり言って大昔の遺物だし, しかも一部のシステムで使われていただけなので今時こんなものを使うべきではない. 特別な事情 (後述) がないのに使えば「嘲笑とクレームの的」になることを覚悟してください.
大昔 (1980年代) の CP/M や MS-DOS 時代のテキストファイルの一部は終端文字としてこの「EOF 文字」を使っていたけど,これは文字コードの規格とは全く関係がなく,OS (CP/M) の制約に由来する仕様.
CP/M ではファイルを128バイトのブロック (フロッピーディスクの1セクタ)
単位でしか管理できなかったため,テキストファイルでは最後のブロックの余った領域
(1〜127バイト) を全部 0x1A
で埋めていた.したがってテキストのサイズが丁度128バイトの倍数ならば,0x1A
は存在しない.このため CP/M の 0x1A は EOF 文字ではなくフィラーという方が正しいし,文字コードではないので
ASCII の SUB (=0x1A) とは何の関係もない.
○ちょっと修正 (2013/03/29(金))
上に書いたとおり ASCII の SUB に EOF の意味はないが, (通信エラーや文字コード変換エラーなどにより発生した) 無効な文字コードを置き換える (SUBstitute) ための制御文字なので,CP/M のテキストファイルでは余白を埋めるためにこの「有効な文字ではないもの」 を使ったのかもしれない.(推測)
参考:JIS X 0201 での SUB の定義
(手元にある「JISハンドブック 情報処理 ソフトウェア・符号編 (1994)」から)
SUB:置換キャラクタ (Substitute Character)
無効又は誤りとなったキャラクタを自動的に置き換えるのに用いる置換用の特殊機能キャラクタ.8.3 制御機能の定義
8.3.144 SUB 置換 (SUBSTITUTE)
SUB は,不当又は誤りと判明した文字に置き換えて使う. SUB への置き換えは,自動的な手段で起こる.
MS-DOS はファイルを1バイト単位で管理できるので CP/M ファイルのようなフィラーは本来不要なのだが,CP/M 用のソフト (メジャーな英文ワープロソフト WordStar など) が MS-DOS に移植されたため,CP/M で作成されたファイルがそのまま MS-DOS でも使われることが多かった. MS-DOS は CP/M のフロッピーディスクを読むことができたので,テキストファイル末尾の 0x1A に対処しなければならなかったのである.
そして CP/M テキストファイルが「テキストファイルの最後には1バイトの 0x1A
を付ける」という仕様に誤解されて広まったのが
EOF 文字の由来だと思う.
(CP/M テキストファイルを読み込むアプリケーションの開発者が「最初の
0x1A を読んだ時点で EOF
と判定する」ように実装したロジックが,そのままファイルの仕様だと誤解されたのだろう.
もっとも上記のとおり,実際の CP/M ファイルでは 0x1A が存在しない場合もあるので,
この判定条件だけでは不十分である.)
もし1980年代に MS-DOS で開発されたシステムや,
それらのファイルを引き継いだシステムがいまだにどこかで動いているのなら,
それらとの間で受け渡すファイルには EOF 文字を使わざるを得ないだろう.
(実例 → 【C#】EOFの文字コード(制御文字?)ってありますか? (@IT会議室))
しかしそんな必要性もないのに今更 EOF 文字なんか使おうものなら, 嘲笑とクレームの的になるだろう.
もっとも,現在でもこの EOF 文字が使われているところがある.それはファイルではなく,
Windows のコマンドプロンプトでのキー入力である.(GUI ではない)
コンソールアプリの入力はキーボードだけなので,
キー入力が終了したこともキー入力で知らせる必要がある.
CTRL-Z を押すと,OS または標準Cライブラリのどちらか
(ちゃんと調べてない) が入力終了と判断し,
Cの標準入出力ライブラリはコンソールアプリに対して EOF に達したことを知らせる.
アプリに通知されるのは EOF (という状態) であって,入力された文字コード
(CTRL-Z=0x1A) ではない.
なお上に書いたとおり,UNIX/Linux
では CTRL-Z ではなく CTRL-D (ASCII EOT) が用いられる.
■参考
2013/03/10(日) | 作成 |
2013/03/29(金) | 少し修正 |
2015/02/09(月) | 少し追記 |
2016/04/09(土) | わずかに追記 |
ASCII の NUL の符号位置は 0x00,DEL は 0x7F であるが, そうなっている理由には元々物理的必然性があった.
ASCII が制定された当時,デジタル記録媒体として紙テープが使われていた (1980年代初め頃まで). 紙テープは,穴が空いている状態が '1' を,穴が空いていない状態が '0' を表す. したがって紙テープの未使用の (まだ文字が書き込まれていない) 部分は 0x00 である.これを空文字 (null,ASCII の文字名は NUL) と定義した.
紙テープ上に記録された文字を削除したい場合には, 専用の器具を使ってすべてのビット位置に穴を空ける. つまり 0x7F であり,これを削除済 (DELeted) と定義した.
現在では DEL は,(文字などを) 削除するコマンドとして使われることが多いが, 本来は削除コマンドではなく文字が削除された痕跡であった. DEL を削除コマンドとして使用するのは,単にその文字名を流用しているだけであり, ASCII 本来の意味とは関係ない.
まとめると,
どちらの場合も,読むべき文字が存在していないのだから, 紙テープ読み込み時には無視 (読み飛ば) すべき文字コードだったのである. しかしこれらの本来の意味は,紙テープとともに廃れてしまった.
ちなみに空文字を NULL や null と書いてしまうと,プログラミング (特に C/C++/Java 等) の文脈では NULL ポインタと混同するおそれがある (実際そういう人がいる) ので,NULL ではなく NUL と表記する方がいいと思う.(それでも混同する人はいるだろうが.)
2013/03/29(金) 追記
上で SUB について触れたが,DEL も SUB も無効な文字を表すという点で似ているといえるかもしれない.DEL の方は人間が (紙テープ上の文字を) 削除した痕跡であるのに対し,SUB の方は自動的に無効と判定された文字の痕跡である.
■参考
|
インターネット時代の文字コード posted with amazlet at 10.07.08 小林 竜生 共立出版 売り上げランキング: 498047 おすすめ度の平均: 文字コードと文字フォントとコード処理方法 |
2007/08/03(金) | 作成 |
2013/03/29(金) | 少し修正 |
2015/02/10(火) 2015/02/11(水) |
少し追記 |
文字コード処理に役立つ (と思われる) データファイルを随時掲載します. ただし,筆者の理解不足や誤解により誤ったデータがあるかもしれませんので, ご利用は自己責任で.
データ形式は主として CSV と,Cのプログラムですぐ利用できる (構造体) 配列のソースにする予定.
「Shift_JIS (または CP932,Windows-31J) コード表」などで検索してくる人が多いので追加.
現在の表示環境で表示可能なシフトJISの2バイト文字を区点番号表で示す (1バイト文字については JIS X 0201 を参照). 1〜120区を収録してあるので,Shift_JIS (標準的なシフトJIS) が使用する2バイト文字集合である JIS X 0208 (1〜94区) だけでなく, Shift_JIS のベンダ拡張版である Windows-31J (CP932),MacJapanese 等の文字も表示可能.
このファイル自身,シフトJISコードで記述しているので, JIS X 0208 以外の文字がどう表示されるかは, このファイルの表示環境に依存する.Windows 環境では Windows-31J が,Mac では MacJapanese が,UNIX 環境では (たぶん) JIS X 0208 の文字集合だけが表示されるだろう. (ファイル内の機種依存領域の説明は,Windows-31J および NEC PC-9800 のものである.MacJapanese については Wikipedia を参考に記入.)
「シフトJIS / JIS X 0208 文字コード表」というタイトルだが, シフトJISのコード値ではなく区点番号で表示している.理由は,
JIS第1水準漢字 (16〜47区) は読みごと,第2水準漢字 (48〜83区 (1983年以降の追加分を除く)) は部首ごとに区点番号表を分けている.
注意:このファイルを別の文字コードに変換する場合, JIS X 0208 で定義されている文字以外は変換条件に応じた文字だけが表示されたり, 文字化けしたりする可能性がある.
ShiftJisTable.txt ダウンロード (プレーンテキストファイル (シフトJIS),92KB)上記「シフトJIS / JIS X 0208 文字コード表」を, Windows API の MultiByteToWideChar() で Unicode に変換したテキストファイル. Unicode なので Windows-31J の機種依存文字も文字コード上は機種依存ではなくなっているが, 表示環境の Unicode フォントがこれらの字形を持っていなければ表示できない点に注意. また MultiByteToWideChar() は Windows-31J の未定義/予約部分を Unicode の私用領域 (Private Use Area) に変換する (詳細は調査中) ので,その表示についても機種依存となる.
Windows-31J の文字集合を調べるだけでなく,MultiByteToWideChar() が Windows-31J (特に未定義/予約部分) をどのように変換するかを調べるためにも使用できる.
Windows-31J.zip ダウンロード (UTF-8 + UTF-16(BE),59KB)行き当たりばったりにブックマークした,文字コード関連のリンク集 (未整理,敬称略) です.
UnicodeとUTF-8の違いを理解していない方が結構居るようなので、文字コードの考え方を元に解説してみようと思う。
2014年9月29日から10月3日にかけて、スリランカのコロンボで国際文字コード規格を審議するWG2会議が開催された。この会議において、WAVE DASH(符号位置U+301C)の例示字形を変更をする提案、文書番号「N4606」が審議され、特に反対が出ないまま、無事に勧告として承認された。この勧告は、今年中ごろに発行を予定されるUnicode 8.0でも反映される予定だ。
JIS X 0213利用者有志による、相互扶助を目的としたウェブサイトです。
このサイトはβ版です。
『漢字データベースプロジェクト』は、Unicode / UCS (Universal Multiple-Octet Coded Character Sets) によって符号化された漢字(CJK統合漢字) の情報交換・検索照合・分析に役立つ様々なデータベースを整備することを目的に、 2003年度に日本学術振興会科学研究費補助金・研究成果公開促進費(データベース) の援助を受けて開始しました。
各種漢字データファイルは、GitHubにて管理されており、 GitHubサーバから取得することができます。
当サイトは多漢字字形処理の環境整備を目的としたさまざまな技術の紹介や議論の場の提供を最終目標としていますが、現状では個人的な研究紹介のためのサイトとなっています。
花園フォント(花園明朝)は自由かつ無償の大規模フリー漢字フォントです。 非漢字は含まれません。現在は明朝体フォント1ウェイトが提供されています。
ラテン文字などの拡張補助文字や人工文字など特殊文字に関するウィキです。
グリフウィキ(GlyphWiki)は、漢字グリフ(漢字字形)を登録・管理し、皆で自由に共有することを目的としたウィキです。
最近、文字列検索ライブラリを作成して気づいたのだが、C++ の標準ライブラリ cctype で定義されているグローバルな文字分類関数は、はっきりいって使ってはいけない。 非常に遅いのである。(中略) 一方、従来の C のやり方だと、(中略) 実に 8 倍以上の開きがある。なぜこんなことになっているのだろうか。
1990年代前半までは、銀行システム、鉄道運行システムなどの社会インフラ系システムにはEBCDICが溢れていたが、2000年問題を超える際にほとんどの汎用コンピュータは姿を消したと思われる。しかし不幸にも、この文字コードに遭遇した場合のために、次ページ以降に4種類のEBCDIC(EBCDIK)コード表を掲げる。
本稿は,POSIX において定義されている文字コード変換関数である iconv の Citrus Project における実装について述べたものである.本稿では,Citrus iconv の実装についての詳細を述べ,本 iconv 実装の利点および欠点について議論する.
深沢 千尋 ラトルズ 売り上げランキング: 46194 おすすめ度の平均: 隠れた名著まぁまぁ 類似所の中では大変読みやすい書籍 面白いです。 |
著者ブログ
|
Unicode標準入門 posted with amazlet at 10.04.13 トニー グラハム 関口 正裕 翔泳社 売り上げランキング: 210985 おすすめ度の平均: ISO/IEC 10646Localization、Internationalizationの虎の巻です |
|
プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ) posted with amazlet at 10.04.13 矢野 啓介 技術評論社 売り上げランキング: 1383 |
Unicode Standard, Version 5.0, The (5th Edition) posted with amazlet at 10.04.13 The Unicode Consortium Addison-Wesley Professional 売り上げランキング: 77034 |
|
CJKV日中韓越情報処理 posted with amazlet on 07.05.07 ケン ランディ Ken Lunde 小松 章 逆井 克己 オライリージャパン (2002/12) 売り上げランキング: 177876 おすすめ度の平均: 分厚い。 |
|
文字符号の歴史―欧米と日本編 posted with amazlet on 07.05.07 安岡 孝一 安岡 素子 共立出版 (2006/02) 売り上げランキング: 174787 |
Unicode IVS/IVD入門 ―JIS規格の歴史、異体字問題の解説から、Windows 8での対応方法まで posted with amazlet at 13.04.19 田丸健三郎 小林龍生 日経BP社 売り上げランキング: 179,480 |
■関連リンク
Office IVSは、IVSフォント非対応のOffice環境で、IVS文字が使えるようになるOffice用のアドインソフトです。
JISハンドブック 情報基本
文字コード関連規格 (JIS X
0201,
0202,
0208,
0209,
0212,
0213,
0221 (Unicode))
や用語集などを含む,情報処理関連 JIS 規格.
|
Copyright © 2007-2020 noocyte. E-mail: relipmoced (a) yahoo.co.jp (" (a) " を半角のアットマークに書き替えてください.) リンクはご自由に. 「noocyte のプログラミング研究室」トップページに戻る. |