[6] 文字列をある文字コードから他の文字コードに変換することを、 一般には文字コード変換といいます。
[16] 文字コードを変更する操作 (演算) は一般に変換, convert, conversion のような語で表すことが多いようです。
[17] 関数名等としては from や to と文字コードの名称をつなげるなどして組み立てることが多く、 変換操作の動詞を含まないこともしばしばあります。
[322] Python では変換器を codec と呼んでいます。この言葉は媒体の符号化の分野で符号化方式やその実装に言及するときに使いますが、 文字符号化の分野ではほぼ使わず、おそらく Python 界隈だけの独特の風習です。
[324] 文字コードの変換とよく似た、ときに混同され、ときに併用・連結される処理に escape / unescape があります。
[13] バイト列を文字列データ型の値に変換することを復号、 文字列データ型の値からバイト列に変換することを符号化といいます。
[15] 現代のプログラミング言語等では内部データを Unicode文字列とすることが多いので、 Unicode への変換を復号、Unicode からの変換を符号化のように言っているかのような使われ方をされがちですが、 厳密な語法ではありません。
[4] 文字列をある文字コードから他の文字コードに変換することを、 転符号化といいます。 転符号化するソフトウェア部品を、 転符号化器といいます。>>1
[5] あまりメジャーな語ではありません。
Transcoding is the process of converting text data from one character encoding form to another. Transcoders work only at the level of character encoding and do not parse the text. Note: Transcoding may involve one-to-one, many-to-one, one-to-many or many-to-many mappings. Because some legacy mappings are glyphic, they may not only be many-to-many, but also discontinuous: thus XYZ may map to yxz. <CHARMOD>
In this definition, "many-to-one" means a sequence of characters mapped to a single character. The "many" does not mean alternative characters that map to the single character.
[2] RFC 6365 - Terminology Used in Internationalization in the IETF ( 版) http://tools.ietf.org/html/rfc6365#page-7
[3] Character Model for the World Wide Web 1.0: Fundamentals ( ( 版)) http://www.w3.org/TR/charmod/#sec-Transcoding
[173] 文字コードの変換の操作は、文字列の意味に影響を与えることがあります。
[174] UTF-8 と UTF-16 の変換のように同じ文字の定義を共有する文字コード体系同士の変換であれば、 技術的な表現方法の機械的な変換にとどまりますから、文字の意味には影響が及びません。
[175]
UTF-8 と EUC-JP の変換のように異なる符号化文字を扱う文字コード体系同士の変換だと、
変換によって文字の意味に影響が出てしまうことがあります。
例えば UTF-8 (Unicode) の鴎
と
EUC-JP (JIS X 0208) の鴎
は、
厳密には意味が異なります。変換はこの微妙な意味の違いを無視する操作となります。
[176] 変換の一方の文字コードにのみある文字が含まれる場合など、 「微妙な意味の違い」を超えた無視できない違いを生じる場合もあります。 詳しくは本記事の各項を参照。
[177] >>175 >>176 の要素を含む文字コードの変換は、破壊的な操作です。 無闇矢鱈と行うべきではありません。
[301] 様々な歴史的事情によって、意図的に別の文字への変換がなされることがあります。
U+0000
, U+007F
] に対応付ける実装があります。0x5C
は YEN SIGN
ですが、
無視して Unicode の U+005C
に対応付ける実装が大多数です。
日本市場では
Unicode の U+005C
が YEN SIGN
の字形で表示されるフォントが多く流通しています。[19] 文字コードの変換の操作は次のような形態のいずれかで実装されていることが多いようです。
[29] >>18 >>22 >>23 はプラットフォームの API として提供されていることもあれば、 アプリケーション等が独自に実装する場合も多いです。
[32] >>18 >>24 は独立したプログラムとなっている場合が多いです。 >>18 はこの場合テキストファイルの変換操作と言えます。
[33]
>>28 は Webページで textarea
等を使った変換ツールとして提供されているものです。
それと同等のライブラリーとして提供されている場合もあります。
8ビット符号の変換器を称していても、
実態は8ビット符号から変換された Unicode文字列同士の変換になっています。
[34] >>24 >>26 は Webブラウザーやワープロ等のソフトウェアの内部で動作するブラウザー拡張やマクロのような形になっているものです。 文字列だけでなくフォント名が変換に関与します。
[41] 入出力の文字コードは、多数に対応しているものもあれば、 特定のものに限られている実装も多いです。 ただし、 多数に対応しているものでも、古今東西の膨大な数の文字コード技術の中の限られた一部のものにしか対応できていません。
[43] 多くの実装は対象となる地域や言語に関係する文字コード群にしか対応していません。 20世紀には当該システムで採用している文字コードを中心に、 それとその他の文字コードとの変換という形態が多く見られました。 21世紀になると Unicode を中心に、 それとその他の文字コードとの変換という形態が一般化しました。
[42] 実変換処理の定義を宣言的な外部ファイルに分離するなど拡張可能な設計になっているものもありますが、 そうでない固定のものもかなり多いです。 拡張可能なものであっても、外部ファイルの記述力には限界があり、 複雑な変換は実装できません。
... するものもあります。
[137] 文字コード体系によっては、同じ文字の表現方法に揺れ、曖昧性、その他本記事の各項に挙げるような選択肢が存在することがあり、 それらを動作オプションとして指定できるものもあります。
[45] 変換不能な場合にエラーとするか、 escape 等に置き換えるか、 代替文字に置き換えるか、置換文字に置き換えるかなどを動作オプションとして指定できるものも多いです。
[44] GUI やワープロソフトウェアのマクロのような形態のものは、 動作オプションやエラーの処理などを通知したり、確認したり、選択させたりしているものもあります。
[48] HTML や RTF やワープロソフトウェアの独自形式のファイルなど、 単純バイト列やテキストファイルとしての変換処理ができず、 ファイル形式とフォント名に応じた処理が必要となる場合があります。
[178] JavaScript によって DOM 上に挿入された文字列のように、 HTML ファイルの静的な変換ではなく >>26 方式で実装された変換器が必須となる場合があります。
[271] 実務上は、処理を途中で停止したり、中断・再開したり、 ネットワークから追加のデータが到着するごとに続きを処理させる形態にしたり、 といった仕組みが必要になることがあります。 (>>269 も参照。) こうした措置をプログラミング言語の組み込みのデータ型や制御機構で自然に実現できる場合もあれば、 独自の設計が必要となる場合もあります。
[275] 入力が1バイト符号だけならバイト列を分割して読み取って変換器の入力としても、 出力を単純につなぎ合わせるだけで済みます。
[276] 入力に複数バイトの符号が含まれたり、状態を持つ文字コード体系だったりすると、 分割して変換した出力の連結は全体の変換結果と一致しないことが多くなります。
[273] 入力が空文字列や数バイトの短いバイト列であることもあれば、 数GBの長大なバイト列であることもあります。 こうした普通でない入力に対する設計や動作検証はなおざりにされがちなようで、 不具合を抱えている実装の事例も散見されます。 セキュリティーの問題となることもありますから、 注意が必要です。
[138] 現代の多くのプログラミング言語にはバイト列と文字列の区別があります。 また、 HTML や RTF やその他の文書形式のデータ構造は、 文字列を構成要素としていることが多いです。
... の4通りがあり得ます。
[181] 言語情報, bidi, フォント, 装飾, その他の付加情報の付随する構造を考慮すると、 組合せは更に増えます。
[183] 古典的な文字コードの変換の実装や、単独の文字コード対の実装は、 単純にバイト列からバイト列への変換としていることが多いです。 複数の文字コード対に対応するときは、 単体の変換の実装を増やしていくことになります。
[184] 多数の文字コードの変換に対応する実装は、 特定の文字コードを「中心」に、それと各種文字コードの変換を実装する形態としていることが多いです。
[185] 現代の実装はプログラミング言語の文字列型の文字列を「中心」 とすることが多いです。現代のプログラミング言語の文字列型の文字列は、 ほとんどの場合 Unicode文字列です。従って Unicode からの変換、 Unicode への変換ということになります。
[186] 古くからの実装は、 Unicode ではない内部符号を使っていることがあります。 新しい実装であっても多くの文字コードに対応する実装は独自の内部符号を採用していることがあります。
[193] 完全独自の内部符号ではなく、 PUA を使ったり、 文字に付随する文字とは別の情報を組合せたりすることもあります。
[159] 実装の都合 (例えば多数の文字コード体系の相互変換のための中間符号としての利用) のために、 入出力の文字コードと無関係の文字コードを利用する場合があります。
[160] 中間符号は、入出力として現れにくいものが選ばれますが、 設計者の判断と利用者の用途が一致するとは限らず、 意図しない結果になる場合もあります。
U+3000
からの領域や U+0FFF
が使われています。U-00110000
以上の領域が使われる場合があります。
[164] ワープロのマクロとしての変換器の実装は符号位置とフォントの組を変換の入出力に使うことがあります。 同じ符号位置でもフォント名が違えば別の文字扱いになり、 変換対象にしたりしなかったりできます。 実在しないダミーのフォント名を使ったり、 実在のフォント名であっても多段変換のどの段階で変換するかを調整することで、 中間符号を用いる方式と同様の効果を実現している場合があります。
[187]
内部符号等が扱う Unicode だけでない情報の例
[188] 現代のほぼすべてのデータ (過去からデータ形式の変換により引き継がれたものを含みます。) は8ビットバイトで記述されています。
[189] 7ビット符号は多いですが、実際の処理では8ビットバイトの列として扱うことになります。
[190] 歴史的には6ビットや9ビットなど異なる単位もありますし、 バイトより大きな単位が実処理の最低単位となることもありますし、 プロトコルやデータ形式が8ビット以外の単位で区切っていることも多々ありますが、 現代の計算機上の文字コードの処理の入出力となる段階では8ビット単位となっており、 変換の処理がそれ以外を想定することはまずありません。
[191] 理屈の上では16ビット符号や32ビット符号など、より大きな単位を束ねた符号体系もいくつもありますが、 それらも結局のところは符号空間の大きさに過ぎないのであって、 それが最低の処理単位となるプラットフォームは極めて稀です。 よって、壊れたデータが端数のバイトを持つ場合や、 ネットワーク転送時のパケット境界が文字の途中で出現する場合などを文字コードの変換の処理は考慮する必要があります。
[192]
Base64 や application/octet-stream
のように端数のビットを扱える (扱えてしまう) (こともある) データ形式もありますが、
それを文字コードの変換の実装と組合せて利用できる実装はほとんどありません。
[194]
C言語など NULL
を文字列の終端とするプラットフォームもありますが、
そうしたプラットフォームの文字コードの変換の実装であっても、
入出力のバイト列の途中で 0x00 が出現する文字コード体系や、
入出力の文字列が NULL
を含む場合を適切に処理できる必要があります。
[232] 入出力の文字コードの指定は、 文字コードの識別子を明示的に与えるものもあれば、 関数名等に組み込まれているものもあります。
[233] 入出力の各種の動作オプションまで含めた文字コードの名称・定義を提供しているものもあります。
[47] 入力となる文字コードの明示的な選択を省略し、 文字コードの判定に拠るものもあります。
[234]
HTML や RTF など、文書形式自体に文字コード決定の機構が組み込まれているものもあります。
[235] フォント依存符号化を使った HTML や RTF のように文字コードの指定が多層的になる場合もあります。 通常は上層は記述されたフォント名により自動的に決まりますが、 上層まで含めた全体の文字コード名が指定された場合の処理、 上層のフォント名が実態と合っていないため無視して上書きする動作オプションの提供など、 実装上考慮するべき特殊ケースもあります。
[236] 原理的に RTF で使いようがない文字コードなど、 文字コードの指定と文書形式の指定が矛盾する組合せが存在するため、 実装上は注意が必要になります。
[145] 文字コードの変換の操作と関係して、文字コードの変換が可能かどうかを決定するという操作が必要となる場合がたまにあります。
charset
について「最小公倍数」を指定することを求めていました。
例えば ASCII文字のみで構成されるなら、 ISO-8859-1
よりも US-ASCII
と指定するのが良いとしていました。 ISO-2022-JP
を使い、それで表せない文字が含まれる時 UTF-8 を使う機能を有するものがあります。[149] こうした機能は実際に変換を行いながらエラーを検出する形で実装される場合もあれば、 事前に高速に判定する手法により実装される場合もあります。 どちらが好ましいかは使い方によりますが、後者の場合は実際の変換処理と乖離するリスクがあります。
[325] 変換処理の実装戦略は様々ですが、その性格はいくつかの要素に分解できます。
[50] 一対一対応が存在する場合、入力を機械的に変換して出力するだけですから、 変換器は非常に単純になります。
[51] すべての符号が一対一対応可能な文字コード体系間の変換は、 宣言的な変換表を用意して外部化することで、容易に対応体系を増やすことができます。
[49] 平成時代初期くらいまでに欧米企業が進出していた地域の標準的な文字コードの文字のほとんどは、 Unicode と一対一対応が存在します。 また、同じ地域の同じ言語を対象とする他の文字コードとも1対1対応が存在する文字が多いです。
[52] ある文字コードで1文字として扱えるものが、他の文字コードでは複数の文字の列になることがあります。
[54] 一対一対応限定の実装より少し面倒になりますが、容易に実装できます。
[59] 西暦1990年代初頭頃に欧米企業が実装していなかった文字コードにある文字は、 それが他の Unicode文字の組合せで表現できると判断された場合 Unicode に追加されないことがほとんどなので、 それらから Unicode への変換でこのパターンとなります。
[55] ある文字コードで複数の文字の列で表されるものが、他の文字コードでは1文字となることがあります。
[56] 複数の文字のそれぞれが変換先の文字コードにも存在するなら、 1対1対応とみなして単純に変換することも可能です。
[57] 複数の文字のいずれかが変換先の文字コードに存在しないなら、 文字列を1文字に変換する必要が出てきます。
[61] 入力があってもすぐに変換先を確定できず、数文字読み続けて適切な出力文字を選ぶ必要が出てきますから、 変換処理は複雑になってきます。
[60] 1文字対多文字対応の変換の逆方向でこのパターンとなります。
[62] ある文字コードで複数の文字の列で表されるものが、 他の文字コードでは複数の文字の列で表され、 両者の構成する文字それぞれに直接的な対応関係がないことがあります。
[63] インド系文字の文字コードなどと Unicode との変換のように、 なにを符号化文字の単位とするかの考え方に大きな違いがある場合に、 この種の変換が頻出することになります。
[64] 変換処理は相当に複雑になります。
[277] ある文字コードの文字(列)から他の文字コードの文字(列)への変換が、 入力文字コードの文字(列)の複雑な条件という形で記述・実装されることがあります。
[278] 汎用の正規表現エンジンで実装されることもあれば、 独自の状態機械などの形で実装されることもあります。
[279]
固定長ではない文字列になることもあります (+
, *
など)。
[280] 記述には文字クラスが使われることもあります。 文字クラスの否定が使われることもあります。 1文字だけの小さな文字クラスもあれば、 十数万字の大きな文字クラスになることもあります。
[281]
記述には選択 (|
) が使われることもあります。
[283] 記述形式によっては文字列や空文字列も文字クラスの要素とできることがあります。 実効上は選択と等価です。
[282] 文字クラスや選択は基本的には複数の置換規則に展開できます。 ただ文字クラスの展開は文字数が多すぎて現実的でないこともあります。
[286] 対象部分文字列のうちの一部分が、置換先で使われることがあります (capture)。 実例をみていくと、
のような用途があるようです。
[291] 順序入れ替えのように、置換前と置換先とで出現順序が変わることも少なくありません。
[292] 1つの変換の条件で出現する capture の数は1個、2個程度のものが多く、 5,6個に達するものは珍しいようです。
[290] 対象部分文字列が文字クラスや選択で記述されているとき、 置換先では写像からそれに対応付けられた文字を選ぶ形になっていることもあれば、 部分文字列だけに適用される規則群の形で記述されていることもあります。
[98] ある文字コードの文字(列)から他の文字コードの文字(列)への変換が、 入力文字コードの文字(列)とその前後の文字(列)の条件という形で記述・実装されることがあります。
[99] 単純な多文字からの変換に置換できる場合も多いですが、 それでは変換表が巨大になりすぎてしまう (数千から無限大の規模となる) とき、 先読み・後読みのような手法で実装されることになります。
[100]
条件部は固定長ではない文字列になることもあります (+
, *
など)。
[262] 条件部の記述には文字クラスが使われることもあります。 文字クラスの否定が使われることもあります。 1文字だけの小さな文字クラスもあれば、 十数万字の大きな文字クラスになることもあります。
[284]
条件部の記述には選択 (|
) が使われることもあります。
[285] 記述形式によっては文字列や空文字列も文字クラスの要素とできることがあります。 実効上は選択と等価です。
[101] 条件部は文字列先頭、文字列末尾、語境界、空白といった形で記述・実装されることも多いです。 こうしたものは語頭形や語末形のような文字列中の文字の位置によって変換を制御する必要がある場合に使われがちです。
[260] 条件部は一致するべき条件が記述されることもあれば、 一致しないべき条件が記述されることもあります。
[261] 一致する、しないの条件と先頭・末尾・境界が一致するかしないかは、 条件の記述方法や正規表現エンジン等の利用方法によって変わってくるので要注意です。
[102] いずれの場合も変換処理は相当に複雑になります。
[103] 意図を正確に記述できているのか疑問が残る実装も散見されます。
[104] >>101 のように本来同等の条件を意図していたと思われるものが実装ごとに違った形で記述されていることもよくあります。 同じような条件を移植していても、プログラミング言語等で挙動が微妙に異なると思われるケースもあります。
[105] 実装の正しさの評価や他の実装との比較が困難になりますから、 可能であれば避けるべきなのでしょうが、避けることが困難と思われるケースも多いです。
[65] 入力文字コードの1つの文字に相当する出力文字コードの文字(列)に複数の候補がある場合があります。
[66] 出力の文字(列)が互いに同等なら、どれを選ぶかは実装者の任意の選択となります。 ライブラリーの類なら応用に動作オプションとして指定させる場合もあります。 プラットフォーム等で慣習が成立している場合もあります。 慣習とならず相互運用性の問題が起こることもあります。
[67] Unicode への変換で、 基底文字と結合文字の組合せを出力するか、 合成済み文字を出力するかの選択肢が存在することがあります。 一般的には合成済み文字が適切と考えられていますし、 1対1対応の変換にできるので実装も単純化できます。
[70] 出力の文字(列)が同等とはいえないなら、どれを選ぶかは文脈その他によって決めることになります。
[71] 前後の文字列との組合せで決められるなら多文字対多文字対応のような形で変換できますが、 多くの場合は機械的に選択することが困難です。
[72] 機械的に決定できなければ、不適切な場合があることを承知の上でどれかを選ぶか、 GUI による選択などの手段で個々に決めるなどの方法になります。
[73] 多くの場合はデータの劣化を恐れずどれか1つを選んで機械的に対応付ける方法を採っているようです。
[69] 実装ではなく Wikipedia の記事の対応表などでは、 複数の対応先の候補を併記する形を採っていることがあります。
[75] 入力文字コードの複数の文字に相当する出力文字コードの文字が1つとなる場合があります。 いくつかに分類できます。
[79] >>76 >>77 は実装上は大きな問題はなく、単純に変換すれば済みます。
[81] >>78 は Unicode から従来の文字コードへの変換で実装されていることがあります。 best fit などと呼ばれることがあります。 変換で失われる情報をできるだけ少なくするための配慮として実装されたものでしょうが、 情報の損失がわかりにくくなるという問題があります。
[85] インド系文字の文字コードと Unicode との変換など符号化文字の考え方が大きく異なる文字コード間の変換は、 1パスの単純な変換ではなく、複数回の変形処理の組合せとして実装されていることがよくあります。
[86] 多段変換とすることで記述や実装が単純化することも多いですが、 どんな入力がどんな出力になるかの見通しは悪いことが多いです。
[156]
機能的必然性がなく、実装の容易性のために多段化されているとみられる事例も散見されます。
例えば JavaScript で実装された変換器で、 String
の replace
メソッドを繰り返し適用することで順次文字を置換していくようなスタイルの変換器が多数あります。
[157] 一昔前なら何パスも掛けて文字列を走査するのは無駄が多く、 1パスで文字列の先頭から順に見ていくのが良いとされたのでしょうが、 現在ではパフォーマンス上の違いは微々たるもので、 実装の簡単性と視認性のメリットが遥かに上回ります。 標準メソッドだけで記述できる分、独自にループで1パスで実装するよりも高速になる可能性までありますし、 実装ミスによる不具合のリスクも減ります。
[158] ただしこの手法は入力文字集合と出力文字集合が重ならない場合には安全ですが、 そうでない場合には置換の適用順序が重要になってきます。 ところがこれをあまり意識していないと思われる事例が散見されます。 出力が再度入力条件と一致することによる置換同士の相互作用が意図的と推定できる場合もあれば、 意図的なのかどうかはっきりしない場合も多いのです。 どちらにしても変換処理全体の入出力の関係が不明瞭となりがちで、不具合の温床となっています。 開発者自身が挙動を理解しきれず冗長な置換規則や誤った置換規則を挿入したと思しき事例もあります。
[253] 変換の段 (pass, phase) 数は、 前述の通り実装戦略次第で1パスだったり数十から数百パスだったり様々となります。
[254]
前述の replace
鎖のような実装戦略の場合、
互いに干渉せず同時処理可能なものをまとめると高々二、三十パス程度になることが多いようです。
(もちろん一パスから二、三パス、せいぜい十パス程度に収まるものがかなり多いです。)
中には百数十パスくらいまでしか減らないものもありますが、
同時処理可能かどうかの判定が難しいケースを保守的に数えた結果ですから、
厳密に検討していけばもっと減らせるでしょう。
[255]
TECkit の .map
のように同時処理可能なものをまとめつつ人間の判断で分けた方が扱いやすいものを分ける実装戦略だと、
多くても十数パス程度になるようです。
.map
で記述されたことがない文字コードの方が圧倒的に多いでしょうが、
おそらくこれを大きく上回る複雑さの文字コードは存在していないでしょう。
[87] 変換処理本体の単純化のために別段で正規化の処理が適用されることがあります。
[88] 入力が Unicode のとき、 NFC や NFD を適用することで、 変換処理本体が基底文字と結合文字の組合せか合成済み文字の一方だけを記述することで済ませたり、 結合文字の順序が入れ替わっている場合への対処を省略したりすることができます。
[89] 入力が翻字系の符号化のときで大文字・小文字不区別のとき、 一括してどちらかに統一してから変換処理本体を実行する場合があります。
[90] 入力の文字コードの構造上の理由から変換処理本体が基底文字と結合文字の組合せを出力したり、 合成済み文字を出力したりすることがあり、これを好ましくないと考える場合、 変換処理本体の後に NFC や NFD を適用する場合があります。
[91] こうした処理は変換処理本体の実装コストを削減できますが、 思わぬ副作用を生むこともあり、注意が必要です。
[92] 大文字と小文字の変換はプログラミング言語によって実装が違いますし、 ロケールによって違った変換となる場合もあります。 変換器の実装者がそうした詳細まで細かく注意して設計していないと思われる事例が散見されます。
[256] なお、 Unicode正規化を実装しているかのような説明でありながら、 当該文字コードやその言語に関連がある部分だけしか実装していないようなものもあります。
[93] インド系文字の文字コードと Unicode の変換など、 符号化文字の考え方が大きく異なる文字コードの変換では、 入出力で文字の配列順序を変更しなければならないことがよくあります。
[94] 入力または出力の数文字の部分文字列が特定のパターンに一致するかを判定し、 一致するなら順序を入れ替えるような処理を複数種類適用することになります。
[95] 部分文字列の組み合わせ数が膨大過ぎて、 多文字対多文字対応に展開するのが事実上不可能な場合が多いです。
[96] 実装によって、 出力文字コードへの変換後に正規表現の置換を組合せたり、 正規表現の置換の組合せの後に出力文字コードへ変換したり、 出力文字コードへ変換しながら順序を入れ替える状態機械を実装したり、 内部処理用の中間表現を導入したりと、 様々な実装戦略が採られています。
[97] どの方法も相当複雑になりますし、概略同じ手法でも置換パターンの作り方次第で見かけ上の処理は大きく変わってしまいます。 従ってソースコードを読んで挙動を理解するのは至難の業ですし、 諸実装の特徴を比較することも困難です。
[242] ヘブライ文字の文字コードやアラビア文字の文字コードでは論理順と視覚順の変換処理が必要となる場合が多いです。
[243] 従来文字コード側だけでなく Unicode 側にもbidi 関係の制御の文字が多数あり、 それらの相互作用を考慮する必要があります。
[244] 行の単位を検出し文字の順序を入れ替える必要があります。
[245] 単純な逆順への入れ替えだけでなく、結合文字のように基底文字に付随する文字をグループ化するなど細かな調整が必要となります。
[247] 実装戦略としては、
... の3通りがあります。 完全に分離する方がアルゴリズムとして綺麗でありメンテナンスが容易で不具合を生みにくいと考えられますが、 1パスで処理したい、 >>244 や >>245 のような複雑な処理との組合せで >>250 の方が実装しやすいという状況もあるのでしょう。
[246]
TECkit の .map
のように事前または事後に行うべき処理として分離している記述形式もあります。
[251] 文字コードの変換の処理から視覚順と論理順の処理を敢えて除外することもあります。
[252]
Webにおける文字コードの処理では視覚順の ISO-8859-8 を
Unicode文字列に変換する際に論理順にせず元のままにして、
CSS によって表示する際に通常の bidi の規則を適用せずそのままの順序としています。
[109] 文字コードの変換の処理で変換表の類によらない計算のみで実現できる操作はいろいろあります。 例えば、
ESC
Fe の変換[106] 平成時代初期ごろまでの日本の文字コードの変換は、 JIS X 0208 に基づくシフトJISと日本語EUCといわゆるJISコードの変換が中心で、 簡単な計算で相互に変換できました。
[107] その後 Unicode の普及期には、計算で変換できず数千行の変換表が必要となる Unicode と従来文字コードとの変換は敬遠されがちで、 Unicode 移行の障害となっていました。
[108] Unicode が一般化した現在では、計算機性能の向上もあってこうした問題が意識されることはなくなりました。 しかしシフトJISと日本語EUCといわゆるJISコードの変換も Unicode を介して行われることが増え、 Unicode との対応関係がそれぞれ微妙に異なるために従来なら無劣化で行えた変換でデータ損失が生じるような事態も生じています。
[204] 文字コードの変換の実装は、入力を読み込みながら、 入力文字コードの状態を管理する必要があります。
[205] 入力の状態の例:
˥˩
, ˩˥
[212] Unicode正規化から呼び出される正準再順序付けのように無限の長さの文字列の状態を保持しなければならない処理があります。
[237]
TECkit の .map
は +
や *
などによる任意の長さの列を条件として記述していますが、
一致する最大長を 15 以下に制限しています。
[238] 同じような条件の記述でも、このような長さ制限を設けていないで正規表現の実装に任せたり、 自前でも状態機械により無限の長さを受理したりする実装も多いです。
[239] 自然言語の記述である文字の列であれば、そうした余りに長い文字列が出現することはまずないと考えられるので、 15 など現実的な長さに制限することは合理的な実装上の配慮であり、セキュリティーその他のために望ましくもあります。
[240] こうした長さの上限のない変換条件の記述は、 音節の単位を検出しつつ置換や順序入れ替えを実施したいインド系文字の文字コードの変換処理や、 行単位で順序の入れ替えを実施したいヘブライ文字の文字コードやアラビア文字の文字コードの論理順と視覚順の処理、 語頭形・語中形・語末形の処理などで見られます。
[267] 実装によっては文字コードの判定や翻字・転写の体系とただの English の区別の確立的判定など、符号化手法を判断する処理と変換の処理が結合していることがあります。
[268] 更には HTML の文字コード指定の検知のような文書形式やプロトコルに依存した処理も併合されていることがあります。
[269] HTML における符号化の変更の処理など、文字コードの判定の結果を報告したり、 それに応じて文字コードの変換の処理を再起動したりといった措置が必要になることもあります。
[151] 例えば出力が ISO/IEC 2022 に基づき複数の符号化文字集合を切り替えて使える符号の場合、 変換は入力文字符号から状態と文字符号の組への写像の形で記述されることになります。 出力の状態が現在の状態と同じならそのまま文字符号を出力でき、 現在の状態と異なるなら状態を切り替えてから文字符号を出力することになります。
[152] 同じ入力文字符号に対する出力の候補として、複数の状態とその文字符号がある場合があります。 この場合、現在の状態と同じものがあれば、その候補を選択すると、自然な出力となる場合が多いです。 (出力文字コードの仕様や慣習にも依存します。)
[153]
例えば Unicode から ISO/IEC 2022 に基づき JIS X 0208 と GB 2312 を使える符号へと変換する場合、
一
は JIS X 0208 と GB 2312 のどちらにも存在するので、
現在の状態に応じてどちらを使うかを決めれば、切り替えのための指示シーケンスを節約できます。
[154]
出力の状態切り替えは、 ISO/IEC 2022 のエスケープシーケンスのような文字コード層の技術による場合もあれば、
HTML の font
要素や RTF のフォント切り替えのような文書形式の機能によって行う場合もあります。
[155] エチオピア文字の文字コードやチベット文字の文字コードやギリシャ文字の文字コードなど、 変換処理が入力のフォントの違いを認識したり、出力のフォントを切り替えたりする必要のある構造のものがあります。
[326] 入力の部分文字列がそのまま出力されることがあります。
[327] 入力文字コードと出力文字コードで同じ表現になる文字がある場合があります。
[329] 入出力がほぼ同じでも、バイト列と文字列のようなデータ型の違いだけがある場合があります。 そうした場合の処置はプラットフォームによって異なります。
[332] フォント依存符号化の変換器のように、対象外となる部分は無変換とすることがあります。
[333] ASCII と8ビット符号で構成される文字コードであることを前提に、 ASCII文字列なら文字コードの変換の処理を省略し、 そうでないなら文字コードの変換の処理を実行するような性能向上のための最適化が行われることがあります。
[334] こうした最適化は、例えば多バイト符号の第2バイトに ASCII文字と同じバイトが含まれる場合や、 ISO-2022-JP のような7ビット符号など、設計者の想定不足による不具合を起こすことがありますから、 十分に注意が必要です。
[118] 入力となる文字コードの文字列であるはずのものには、 適切に変換できないデータが含まれていることがあります。
[119] 具体的には
といったものが考えられます。
[123] 歴史的に文字コード関連規格は不正な入力への対処を明確に規定して来ませんでした。 こうしたものに遭遇したときの仕様上の「正しい」挙動が存在しないことが多いです。
[124] 近年の Encoding Standard はあらゆる入力に対する挙動を定めていますが、 例外的な存在です。
[125] こうしたデータに対する処理は実装によって様々です。
[133] このうち >>130 >>131 >>132 はセキュリティー上の問題を起こしかねないですし、 >>129 もライブラリー等で応用の開発者が意図していない場合には好ましからざる挙動となることがあります。 不適切なデータに対する挙動はあまり意識されないことが多いようで、 このような問題を孕んだ実装は意外と多いです。
[136] ただし出力先が HTML や RTF などでフォント指定を伴う場合のように、 >>130 が正当な選択肢となることもあります。
[203] エディター類でファイルを開く場合のように、不正な入力も生のバイトとして他の文字とは区別してそのまま保持できることが好ましい用途もあります。
[179]
置換文字や escape に置き換える手法は非常によく用いられますが、
通常の入力からの変換結果との区別に注意が必要となることがあります。
例えば不正な入力を ?
に置き換えると、
本来の ?
と区別が付かなくなり、問題となる場合もあります。
[180] 多数の文字コードの出力に対応する実装や外部から動作オプションで指定できる実装は、 置換文字や escape が出力先の文字コードに存在しない文字を含む場合の対処にも注意が必要です。
[306] 変換直後に逆変換することを合わせて往復変換といいます。
[307] 文字コードの変換に限った用語ではありませんが、文字コードについて使うことがかなり多いようです。
[308] 往復変換は文字コードの性質や文字コードの変換の性質の評価において重要な観点です。
[319] 往復変換の成否は個別の文字列についていう事もあれば、 文字コード体系全体を総括的にいうこともあります。
[309] Unicode は欧米の主要な文字コードの文字をすべて収録しているため、 そのような従来文字コードから Unicode に変換し、 従来文字コードに戻すような往復変換では情報の損失がほとんど発生しません。
[311] 往復変換の安全性は、逆転させると違うことがあります。
[313] アジアの多くの文字コードは >>309 の性質が成り立たないか、 成り立つか自明ではありません。
[314] 個別の実装をみても、順方向と逆方向で処理が対照的になっていない事例が散見されます。 それが意図的なものかそうでないのか、 特定の実装の性質なのか文字コード自体の性質かなど、 判断するのが困難な場合が多いです。 (そういう実装は複雑な変換処理を行っているものなので、判定が難しいです。)
[315] 重複符号化は往復変換が成功しなくなる大きな要因です。
[317] 文字の概念や符号化モデルが違う文字コード体系同士の変換だと往復変換が成功しないことが多くなると考えられます。
[318] 扱う文字が異なる文字コード体系だと往復変換が成功しないことが多くなります。 一方にしかない文字があると当然失敗します。
[316] 往復変換の安全性は文字レベルの情報の損失を基準に議論されることが多いようです。 バイトレベルで複数の表現があり得る文字コード体系だと往復変換によって異なるバイト列となることがあり、 それを往復変換が成功した、していないと議論されることはあまりないように思われます。
[320] 変換表の形で記述される変換は往復変換を前提にしたものが多いです。
[321]
TECkit の .map
のように複雑めな変換を記述できる形式でも、
順方向と逆方向の変換をセットで記述し、共通部分と差分を含められるようにしている場合があります。
[35] CodepageEncoder/data/encodings at main · NielsLeenheer/CodepageEncoder · GitHub, https://github.com/NielsLeenheer/CodepageEncoder/tree/main/data/encodings
[39] Evertype: Unicode Mapping Tables, , https://www.evertype.com/standards/mappings/
[40] sourceware.org Git - glibc.git/tree - iconvdata/, https://sourceware.org/git/?p=glibc.git;a=tree;f=iconvdata;h=494f8c50b9c9662ae85bf56184db943b0526e12c;hb=b2a8d19f4adc8ca22394b02c144b4bc867adc804
[10] xorg / font / encodings · GitLab, https://gitlab.freedesktop.org/xorg/font/encodings
[8] 当初は FTP 配布
[20] General Questions about Chararcter Mappings, , https://web.archive.org/web/19970105193228/http://stonehand.com:80/unicode/faq/mappings/general.html
[21] Questions about Mapping Tables, , https://web.archive.org/web/19970105193219/http://stonehand.com:80/unicode/faq/mappings/tables.html
.map
ファイル[170] 個別の文字コード対の変換操作については20世紀から21世紀初頭の頃に実装戦略が研究されてきているものの、 ソースコード以外にまとまった文章の形となっていない場合が大多数と思われます。
[171] 各種の文字コード技術の変換を包括的に議論したものはほとんどないと思われます。 あるとしても欧米や東アジアの主要な文字コード規格に関するものが中心で、 アジア等の各地で使われたフォント依存符号化系の変換技術や HTML, RTF の処理と組み合わさった変換技術、ワープロのマクロの形の実装手法など、 本格的な研究対象として観察されてこなかったと思われる領域が多いです。
[172] 実装技法も実装そのものも Unicode への移行の進展と共に忘れられつつあり、 技術史の観点から個々の実態調査を進めて全貌を究明し、 要素技術を整理して検証していくことが急務でしょう。
[165] 変換器は古今東西に無数に開発され利用されてきたようです。
[166] その中には十分なテストがされておらず満足に動作しないもの、 致命的な不具合があるもの、 意図した動作なのか疑わしい挙動をするものもあります。
[167] 驚くべきことに、地域コミュニティーの中心的な Web サイトの変換器であってもそのような品質のものが珍しくありません。
[168] また、同じ文字コード体系に対応していると主張する変換器同士であっても、 互いの挙動に違いがあることは珍しくありません。 どちらが正しいか判断できないもの、どちらも違った形で壊れていると思われるものも多いです。
[169] 単純な変換表の形で表現された変換器の実装や明らかに単純な変換をしている変換器の出力なら互いに比較することもできますが、 複雑なアルゴリズムで変換しているものは、ソースコードを慎重に読み込んでも互いの挙動にどのような違いがあるのか理解しづらいことがほとんどです。