慣習なのはわかるけどなんで?他の方法が本当に悪い考えになる本当の技術的な理由はありますか、それともエンコーディングと下位互換性の歴史に基づいているだけですか? さらに、 を使用せずUTF-8
に他のエンコーディング (特にUTF-16
) を使用することの危険性は何ですか?
編集:相互作用することによって、私は主に と を意味しshell
ますlibc
。
ファイル システムが NUL ('\0') バイトがファイル名を終了することを想定しているため、UTF-16 はうまく機能しません。その変更を行うには、多くのコードを変更する必要があります。
jonathan-leffler が言及しているように、主要な問題は ASCII ヌル文字です。C は従来、文字列が null で終了することを想定しています。そのため、標準の C 文字列関数は、ASCII null (0x00) に相当するバイトを含む UTF-16 文字でチョークします。ワイド文字サポートを使用してプログラミングすることは確かにできますが、UTF-16 は、ファイル名、テキスト ファイル、環境変数での Unicode の適切な外部エンコーディングではありません。
さらに、UTF-16 と UTF-32 には、ビッグ エンディアンとリトル エンディアンの両方の方向があります。これに対処するには、MIME タイプなどの外部メタデータまたはByte Orientation Markが必要です。それは、
UTF-8 が 8 ビット環境で透過的に使用される場合、BOM を使用すると、「#!」の使用など、先頭に特定の ASCII 文字が必要なプロトコルまたはファイル形式に干渉します。の Unix シェル スクリプトの先頭。
UCS-2 と呼ばれ、サロゲート ペアをサポートしていなかった UTF-16 の前身にも同じ問題がありました。UCS-2 は避けるべきです。
UTF8 が ASCII で提供するのは、主に下位互換性だと思います。
「危険」の質問に対する答えとして、「相互作用」の意味を明確にする必要があります。シェル、libc、または適切なカーネルと対話することを意味しますか?
最近の Unix は UTF-8 を使用していますが、これは常に正しいとは限りません。RHEL2 では (まだ数年しか経っていません)、デフォルトは
$ ロケール LANG=C LC_CTYPE="C" LC_NUMERIC="C" LC_TIME="C" LC_COLLATE="C" LC_MONETARY="C" LC_MESSAGES="C" LC_PAPER="C" LC_NAME="C" LC_ADDRESS="C" LC_TELEPHONE="C" LC_MEASUREMENT="C" LC_IDENTIFICATION="C" LC_ALL=C/POSIX ロケールは、7 ビット ASCII 互換エンコーディングであると予想されます。
ただし、Jonathan Leffler が述べたように、システム API はロケールに依存しないため、文字シーケンス内で NUL バイトを許可するエンコーディングは Unix では機能しません。文字列はすべて、\0 で終了するバイト シーケンスであると見なされます。
Microsoftが2バイトエンコーディングを使い始めたとき、0xffffを超える文字は割り当てられていなかったと思います。したがって、2バイトエンコーディングを使用することは、文字の長さが異なることを誰も心配する必要がないことを意味します。
この範囲外の文字があるので、とにかく異なる長さの文字を処理する必要がありますが、なぜ誰かがUTF-16を使用するのでしょうか。もし彼らが今日彼らのユニコードサポートを設計していたら、マイクロソフトは別の決定をするだろうと私は思う。
はい、互換性のためです。UTF-8 は ASCII と下位互換性があります。Linux/Unix は ASCII ベースだったので、当然のことです。
ASCII 入力を期待するプログラムが UTF-16 などのエンコーディングを処理できないためだと思います。ほとんどの文字 (0 ~ 255 の範囲) について、これらのプログラムは上位バイトを NUL / 0 文字として認識します。これは、多くの言語やシステムで文字列の終わりを示すために使用されます。これは、埋め込まれた NUL を回避し、バイト順序に依存しないように設計された UTF-8 では発生しません。