UTF-16 ( 16 ビットUnicode変換フォーマット) は、Unicode の有効なコード ポイント 1,112,064 個すべてをサポートする文字エンコーディングです。[ 1 ]コードポイントは1つまたは2つの16 ビットコード ユニットでエンコードされるため、エンコーディングの長さは可変です。UTF-16 は、以前の廃止された固定幅 16 ビット エンコーディングであるUCS-2 (2 バイト Universal Character Set)から生まれました。 [ 2 ] [ 3 ] 2 16 (65,536)を超えるコード ポイントが必要であることが明らかになったためです。[ 4 ]これには、ほとんどの絵文字や、人名や地名などの重要なCJK 文字が含まれます。 [ 5 ]
UTF-16 はWindows APIやJavaやQtなどの多くのプログラミング環境で使用されています。UTF-16 の可変長文字と、ほとんどの文字が可変長ではないという事実 (そのため可変長はほとんどテストされない) が相まって、Windows 自体を含むソフトウェアに多くのバグが発生しています。 [ 6 ]
UTF-16 は、ウェブ上で (現在も) 許可されている唯一のエンコーディングで、8 ビットASCIIと互換性がありません。[ 7 ] [ b ]ウェブ上では普及したことはなく、公開されているウェブページの 0.004% 未満で宣言されています (それでも、ウェブページはUTF-8も使用している可能性が高いです)。[ 9 ]それに対し、UTF-8 は何年も前に優勢になり、2025 年までにすべてのウェブページの 99% を占めるようになりました。[ 10 ] Web Hypertext Application Technology Working Group (WHATWG)は、UTF-8 を「すべての [テキスト] の必須エンコーディング」とみなしており、セキュリティ上の理由からブラウザ アプリケーションは UTF-16 を使用すべきではないと考えています。[ 11 ]

1980年代後半、それまでの言語固有のエンコーディングを1つの統一されたシステムに置き換える「ユニバーサル文字セット」(UCS)のための統一エンコーディングの開発が始まった。目標は、世界のほとんどの言語で必要なすべての文字に加え、科学、数学、音楽などの技術分野の記号も含めることだった。当初の構想は、1文字あたり1バイトを必要とする一般的な256文字のエンコーディングを、1文字あたり2バイト(16ビット)を必要とする65,536(2¹⁶ )の値を使用するエンコーディングに置き換えることだった。
ISO/IEC JTC 1/SC 2とUnicode コンソーシアムの2 つのグループが並行してこの作業に取り組みました。後者は主にコンピュータ機器メーカーを代表しています。両グループは、開発中のエンコーディングが相互に互換性を持つように、文字割り当てを同期させようとしました。初期の 2 バイトのエンコーディングは「UCS-2」と呼ばれていました。[ 2 ] [ 3 ] [ 12 ]
2 16文字では不十分であることがますます明らかになったため、 [ 13 ] IEEE はより大きな 31 ビット空間と、1 文字あたり 4 バイトを必要とするエンコーディング ( UCS-4 ) を導入しました。これは、1 文字あたり 4 バイトではメモリとディスク領域を大量に浪費することと、一部のメーカーがすでに 2 バイト/文字の技術に多額の投資をしていたことから、Unicode コンソーシアムによって抵抗されました。妥協案として UTF-16 エンコーディング方式が開発され、1996 年 7 月に Unicode 標準のバージョン 2.0 で導入されました。 [ 14 ]これは、2000 年にIETFによって公開された RFC 2781 で完全に規定されています。[ 15 ] [ 16 ]
UTF-16は、国際標準ISO/IEC 10646とUnicode標準の両方の最新バージョンで規定されています。「UCS-2は現在では廃止されているとみなされるべきです。10646またはUnicode標準のいずれにおいても、もはやエンコーディング形式を参照していません。」 [ 2 ] [ 3 ] UTF-16は、より多くのコードポイントをサポートしたり、サロゲートに置き換えられたコードポイントをサポートしたりするように拡張されることはありません。これは、一般カテゴリまたはサロゲートコードポイントに関するUnicode安定性ポリシーに違反するためです。[ 17 ] (自己同期コードのままのスキームでは、シーケンスを開始するために少なくとも1つの 基本多言語面(BMP)コードポイントを割り当てる必要があります。コードポイントの目的を変更することは許可されていません。)
各Unicodeコードポイントは、1つまたは2つの16ビットコードユニットとしてエンコードされます。2 16未満のコードポイント(「BMP内」)は、古いUCS-2と同様に、コードポイントの数値に等しい単一の16ビットコードユニットでエンコードされます。2 16以上のコードポイント(「BMP以上」)は、2つの16ビットコードユニットを使用してエンコードされます。これらの2つの16ビットコードユニットは、以前に文字に割り当てられていなかったUTF-16サロゲート範囲0xD800~0xDFFFから選択されます。この範囲の値は文字として使用されないため、UTF-16では、これらを個別のコードポイントとしてエンコードする有効な方法はありません。したがって、UTF-16ストリームは、サロゲート範囲外の単一の16ビットコードと、サロゲート範囲内の16ビット値のペアで構成されます。
UTF-16とUCS-2はどちらも、この範囲のコードポイントを、対応するコードポイントと数値的に等しい単一の16ビットコードユニットとしてエンコードします。基本多言語面(BMP)のこれらのコードポイントは、UCS-2で表現できる唯一のコードポイントです。Unicode 9.0以降、現代の非ラテン文字のアジア、中東、アフリカの文字の一部は、ほとんどの絵文字と同様に、この範囲外となります。
他のプレーンからのコードポイントは、サロゲートペアと呼ばれる2つの16ビットコードユニットとしてエンコードされます。最初のコードユニットは上位サロゲートで、2番目は下位サロゲートです(これらはそれぞれUTF-8の先頭バイトと末尾バイトに類似して、「先頭」サロゲートと「末尾」サロゲートとも呼ばれます。[ 18 ])。
視覚的に表すと、 W1とW2間のU' の分布は次のようになります。[ 19 ]
U' = yyyyyyyyyyxxxxxxxxxx // U - 0x10000 W1 = 110110yyyyyyyyyy // 0xD800 + yyyyyyyyyy W2 = 110111xxxxxxxxxx // 0xDC00 + xxxxxxxxxx 上位サロゲート( 0xD800–0xDBFF )、下位サロゲート( 0xDC00–0xDFFF )、および有効な BMP 文字 (0x0000–0xD7FF、0xE000–0xFFFF)の範囲は互いに重複しないため、サロゲートが BMP 文字と一致したり、隣接する 2 つのコード ユニットが有効なサロゲート ペアのように見えたりすることはありません。これにより、検索が大幅に簡素化されます。また、UTF-16 は16 ビット ワードで自己同期します。つまり、コード ユニットが文字の開始位置であるかどうかは、それ以前のコード ユニットを調べなくても判断できます (つまり、コード ユニットの種類は、それが属する値の範囲によって判断できます)。UTF-8 もこれらの利点を共有していますが、以前の多くのマルチ バイト エンコーディング スキーム ( Shift JISやその他のアジアのマルチ バイト エンコーディングなど) では、曖昧さのない検索はできず、文字列の先頭から再解析することによってのみ同期できました。 UTF-16は、1バイトが失われた場合や、ランダムなバイトから走査が開始された場合、自己同期を行いません。
最も一般的に使用される文字はすべてBMPに含まれているため、サロゲートペアの処理は十分にテストされていないことがよくあります。このため、人気があり評価の高いアプリケーションソフトウェアであっても、バグや潜在的なセキュリティホールが残ってしまうことがあります(例:CVE - 2008-2938 、CVE- 2012-2135)。
公式のUnicode規格では、UTF-16を含むどのUTF形式でもサロゲートコードポイントをエンコードできないとされています。これらは文字として割り当てられることはないため、エンコードする理由はありません。しかし、Windowsではファイル名[ 20 ]やその他の場所でペアになっていないサロゲートが許可されているため、Unicode規格から除外されているにもかかわらず、ソフトウェアでサポートする必要があるのが一般的です。
UCS-2、UTF-8、UTF-32は、これらのコード ポイントを自明かつ明白な方法でエンコードすることができ、標準ではそのような配置はエンコード エラーとして扱うべきであると規定されているにもかかわらず、多くのソフトウェアがそうしています。 UTF-16 の形式では、コード ポイントと同じコード ユニットを使用することで、ペアになっていないサロゲート(低いサロゲート コード ポイントが後に続かない、または高いサロゲートが前に来ない) を曖昧さなくエンコードすることが可能です。結果は有効な UTF-16 ではありませんが、UTF-16 エンコーダおよびデコーダの実装の大部分は、エンコード間で変換する際にこれを行います。[ 21 ]
U+10437 (𐐷) を UTF-16 にエンコードするには:
UTF-16 から U+10437 (𐐷) をデコードするには:
以下の表は、この変換とその他の変換をまとめたものです。色分けは、コードポイントのビットがUTF-16バイト間でどのように分配されるかを示しています。UTF-16エンコード処理によって追加されたビットは黒で表示されています。
UTF-16とUCS-2は、16ビットのコード単位のシーケンスを生成します。ほとんどの通信プロトコルとストレージプロトコルはバイト単位で定義されており、各単位は2つの8ビットバイトで構成されるため、バイトの順序はコンピュータアーキテクチャのエンディアン(バイト順序)に依存する場合があります。
コード ユニットのバイト順序の認識を支援するために、UTF-16 では、最初の実際のコード化値の前に、バイト順序マーク(BOM)、つまり値 U+FEFF のコード ポイントを付けることが可能です。 [ c ] (U+FEFF は、目に見えないゼロ幅の非改行スペース/ZWNBSP 文字です)。[ d ]デコーダのエンディアン アーキテクチャがエンコーダのエンディアン アーキテクチャと一致する場合、デコーダは 0xFEFF 値を検出しますが、逆エンディアンのデコーダは、この目的のために予約されている非文字値 U+FFFE として BOM を解釈します。この誤った結果は、残りの値に対してバイト スワッピングを実行するヒントとなります。
BOMがない場合、RFC 2781ではビッグエンディアン(BE)エンコーディングを想定することを推奨しています。実際には、Windowsはデフォルトでリトルエンディアン(LE)順序を使用しているため、多くのアプリケーションはリトルエンディアンエンコーディングを想定しています。また、U+0100より小さい文字が非常に多いという前提で、ヌルバイトを探すことでエンディアンを検出することも確実です。0から始まる偶数バイトがさらにヌルであれば、ビッグエンディアンです。
この規格では、エンコードタイプとしてUTF-16BEまたはUTF-16LEを指定することで、バイト順序を明示的に指定することも可能です。このようにバイト順序を明示的に指定する場合、テキストの先頭にBOMを付加してはならず、先頭のU+FEFFはZWNBSP文字として扱われるべきです。しかし、ほとんどのアプリケーションはこの規則にもかかわらず、あらゆる場合においてBOMを無視します。
インターネットプロトコルにおいて、 IANAはこれらのエンコーディングの名称として「UTF-16」、「UTF-16BE」、「UTF-16LE」を承認しています(大文字と小文字は区別されません)。UTF_16やUTF16といったエイリアスは、一部のプログラミング言語やソフトウェアアプリケーションでは意味を持つ場合がありますが、インターネットプロトコルにおける標準名称ではありません。
UCS-2BEおよびUCS-2LEという同様の名称は、 UCS-2のバージョンを示すために使用されます。
「文字」は任意の数のUnicodeコードポイント[ 22 ]を使用することができ、UTF-16ではコードポイントは1つまたは2つの16ビット値を使用できます。これは、UTF-16が「文字数を数える」ことや「文字列の幅/長さを測定する」ことには全く役立たないことを意味します。
UTF-16は、 UTF -8では3バイトかかる文字を2バイトで表現できるため、東アジア言語においてはUTF-8よりもスペース効率が良いとよく言われます。しかし、実際のテキストには多くの空白、数字、句読点、マークアップ(ウェブページなど)、制御文字が含まれており、これらはUTF-8では1バイトしか必要としないため、これは人工的に構築された密なテキストブロックにのみ当てはまります。より現実的な主張は、複数の文字からなる単語を使用するデーヴァナーガリー文字やベンガル語に当てはまります。これらの言語では、すべての文字がUTF-8では3バイト、UTF-16ではわずか2バイトしか必要としません。
システムが内部的にどのエンコーディングを使用しているかを判断する方法の一つは、BMP以外の文字を1文字だけ含む文字列の「長さ」を尋ねることです。長さが2の場合はUTF-16が使用されています。4の場合はUTF-8、3または6の場合はCESU-8、1の場合はUTF-32である可能性がありますが、 1の場合は言語が文字列をコードポイントにデコードしてから「長さ」を測定している可能性が高いです。
現在サポートされているすべてのバージョンのMicrosoft Windows [ 23 ] ( Windows CE 5.0以降[ 24 ]およびWindows 2000以降[ 25 ]のWindows NTを含む) のOS APIでは、テキストに UTF-16 が使用されています。Windows 2000 より前の Windows NT は UCS-2 のみをサポートしていました。[ 26 ] [ 27 ] Windows 9x はUCS-2 のみをサポートしており、Unicode のサポートはVFATやWDMなどの内部的なものに限られています。Windows 10 バージョン 1903 (またはInsider ビルド17035) 以降は、API で UTF-8 を使用できるようになりましたが[ 28 ] 、 Windows ファイル エクスプローラーなどのほとんどのソフトウェアは、依然として UTF-16 API を使用しています。Microsoft は、「UTF-16 [..] は、複数のプラットフォームを対象とするコードに Windows が課す特有の負担である」と述べています[ 29 ]
IBM iオペレーティング システムでは、UCS-2 エンコーディングにはCCSID (コード ページ) 13488、UTF-16 エンコーディングには CCSID 1200 が指定されていますが、システムは両方とも UTF-16 として扱います。[ 30 ]
UTF-16は、Qualcomm BREWプラットフォーム、.NET環境、およびQtクロスプラットフォームグラフィカルウィジェットツールキットで使用されています。
CD-ROMメディアで使用されるJolietファイルシステムは、ファイル名を UCS-2BE (ファイル名ごとに最大 64 文字の Unicode 文字) を使用してエンコードします。NTFSとReFS は、文字列を保存するために UTF-16 を使用します。[ 31 ]
SMSテキスト メッセージングは、実質的に UTF-16 を使用します。3GPP TS 23.038 ( GSM ) および IS-637 ( CDMA ) 規格では UCS-2 が指定されていますが、絵文字を機能させるには UTF-16 が必要です。[ 32 ] Nokia S60 および Sony Ericsson UIQハンドセットで使用されているSymbian OS はUCS-2 を使用します。iPhoneハンドセットはUTF-16 を使用します。
Pythonバージョン 2.0 は公式には内部で UCS-2 のみを使用していたが、UTF-8 デコーダーから「Unicode」は正しい UTF-16 を生成した。Python をコンパイルして内部で UTF-32 を使用する機能もあり、これは Unix で時々行われていた。Python 3.3 では、文字列内の最大のコード ポイントに応じて、内部ストレージをISO-8859-1 、UCS-2、または UTF-32 のいずれかを使用するように変更した。 [ 33 ] Python 3.12 では、すべての文字列でUTF-8への移行を容易にするために、一部の機能 (CPython 拡張機能用) を削除した。 [ 34 ]
Java は当初 UCS-2 を使用していましたが、J2SE 5.0で UTF-16 補助文字のサポートを追加しました。メモリ内のすべての文字列は UTF-16 です (Java 9 以降、ISO-8859-1 文字のみを含む文字列はバイトに「圧縮」できます[ 35 ] )。Java の I/O は UTF-8 [ 36 ]またはModified UTF-8 [ 37 ]を使用します。
JavaScriptはUCS-2またはUTF-16を使用する場合があります。[ 38 ]
C# は文字列に UTF-16 を使用します。最近、UTF-8 文字列を使用する機能が追加されました[ 39 ] 。また、それらを使用する .NET 関数もいくつか追加されました[ 40 ]。
Appleが推奨するアプリケーション言語であるSwiftは、バージョン5までは文字列の保存にUTF-16を使用していたが、バージョン5ではUTF-8に切り替わった。[ 41 ]
かなりの数の言語がエンコーディングを文字列オブジェクトの一部としており、UTF-16 を含む多数のエンコーディングを保存およびサポートしています。ほとんどの言語は、UTF-16 と UCS-2 を異なるエンコーディングとみなしています。例としては、PHP言語、[ 42 ] MySQL、[ 43 ]および ES2015 以降の JavaScript が挙げられます。
一部の言語では、非 BMP 文字を UTF-16 文字列定数に入れる唯一の方法は、両方のサロゲート ハーフを記述することです。たとえば、U+1D11Eの"\uD834\uDD1E"代わりに と記述します。"\U0001D11E"
UEFIはデフォルトでUTF-16を使用して文字列をエンコードします。UEFI 2.4以降では、ASCIIのみの文字列をエンコードするためにASCIIを使用することもできます。
各エンコーディング形式は、UnicodeコードポイントU+0000..U+D7FFとU+E000..U+10FFFFをマッピングします。
...] UCS-2という用語は現在では廃止されていると考えるべきである。これはもはや10646またはUnicode標準のいずれにおいてもエンコード形式を指すものではない。
UCS-2 は廃止された用語で、Unicode 1.1 までの Unicode 実装を指します [...]
-16は、単一の16ビットコードユニットを使用して、Unicodeで最も一般的な60,000文字以上をエンコードします。
このトップ 10 リストのアイデアは、10 年以上前に、まだ BMP コード ポイントのみをサポートしている環境がいくつかあったことから思いつきました。もちろん、そのアイデアは、そのような環境の開発者に、BMP を超えるコード ポイントをサポートするように促すため、そうする理由を列挙したリストを提供することでした。そして、確かに、VivaDesigner アプリのように、まだ BMP コード ポイントのみをサポートしている環境がいくつかあります。
ウィンドウダイアログでのファイル名の編集が壊れている(削除するにはバックスペースを2回押す必要がある)
-16エンコーディングは、この仕様でASCII互換エンコーディングではないと扱う必要がある唯一のエンコーディングです。
は、ユニバーサルコード化文字セットであるUnicodeの交換に最も適したエンコーディングです。したがって、新しいプロトコルやフォーマット、および新しいコンテキストで展開される既存のフォーマットについては、この仕様ではUTF-8エンコーディングを要求(および定義)しています。[…] ここで概説した問題は、UTF-8のみを使用すると解消されます。これが、UTF-8がWeb上のすべてのテキストコンテンツの必須エンコーディングとなっている多くの理由の1つです。
[…] ファイルシステムはパス名とファイル名をWCHARの不透明なシーケンスとして扱います。
これらの関数は、WindowsオペレーティングシステムのネイティブUnicodeエンコーディングに使用されるUTF-16(ワイド文字)エンコーディング(…)を使用します。
2000では、補助文字の基本的な入力、出力、および簡単なソートがサポートされるようになりました。ただし、すべてのシステムコンポーネントが補助文字に対応しているわけではありません。
1903 (2019 年 5 月更新)
以降では
、パッケージ化されたアプリの場合は appxmanifest、パッケージ化されていないアプリの場合は fusion マニフェストの ActiveCodePage プロパティを使用して、プロセスに UTF-8 をプロセス コード ページとして使用するように強制できます。[...] これは、
Windows バージョン
1903 (2019 年 5 月更新) 以降で実行され、上記の ActiveCodePage プロパティが UTF-8 に設定されている場合にのみ
有効です
。それ以外の場合は、従来のシステム コード ページが適用されます。明示的に使用することをお勧めします
。
CP_ACPCP_UTF8CP_UTF8
] Windows はネイティブでは UTF-16 (または WCHAR) で動作するため、MultiByteToWideChar および WideCharToMultiByte を使用してコード ページ変換を行う必要があります。これは、複数のプラットフォームを対象とするコードに対して Windows が課す特有の負担です。[...] Microsoft Game Development Kit (GDK) および Windows 全般は、複数のプラットフォームや Web を対象とするコードやそれらとの交換における Windows 特有の負担を取り除くために、UTF-8 のサポートに向けて進んでいます。また、これにより、アプリやゲームにおける国際化の問題が減り、正しく動作させるために必要なテスト マトリックスも削減されます。