まず、Unicodeをよりよく理解する必要があります。あなたの質問に対する具体的な答えは一番下にあります。
コンセプト
プログラミング入門コースで教えられているような非常に単純なテキスト処理に必要なものよりも、より微妙な概念のセットが必要です。
- バイト
- コードユニット
- コードポイント
- 抽象的な文字
- ユーザーが認識したキャラクター
バイトは、アドレス可能なメモリの最小単位です。現在は通常8ビットで、最大256の異なる値を格納できます。定義上、charは1バイトです。
コード単位は、テキストの保存に使用されるデータの最小の固定サイズ単位です。テキストの内容をあまり気にせず、テキストをどこかにコピーしたり、テキストが使用しているメモリの量を計算したりする場合は、コード単位を気にします。それ以外の場合、コード単位はあまり使用されません。
コードポイントは、文字セットの個別のメンバーを表します。文字セットに含まれる「文字」が何であれ、それらにはすべて一意の番号が割り当てられ、特定の番号がエンコードされているのを見ると、処理している文字セットのメンバーがわかります。
抽象文字は、言語システムで意味を持つエンティティであり、その表現またはその意味に割り当てられたコードポイントとは異なります。
ユーザーが知覚する文字は、そのように聞こえます。ユーザーが使用している言語システムのキャラクターとして何を考えているか。
昔は、char
これらすべてを表してchar
います。aは定義上バイトであり、char*
文字列ではコード単位はchar
sであり、文字セットは小さいため、で表現できる256の値はchar
すべてのメンバーを表すのに十分であり、サポートされているのはシンプルだったので、文字セットのメンバーは主にユーザーが直接使用したい文字を表しています。
しかし、ほとんどすべてをchar
表すこの単純なシステムは、より複雑なシステムをサポートするのに十分ではありませんでした。
遭遇した最初の問題は、一部の言語が256文字をはるかに超える文字を使用することでした。そのため、「ワイド」文字が導入されました。ワイド文字は、上記の4つの概念、コードユニット、コードポイント、抽象文字、およびユーザーが認識する文字を表すために、依然として単一のタイプを使用していました。ただし、ワイド文字は1バイトではなくなりました。これは、大きな文字セットをサポートする最も簡単な方法であると考えられていました。
コードは、。の代わりにワイド文字を処理することを除いて、ほとんど同じである可能性がありchar
ます。
しかし、多くの言語システムはそれほど単純ではないことがわかりました。一部のシステムでは、ユーザーが認識するすべての文字が、文字セット内の単一の抽象文字で表される必要がないことが理にかなっています。その結果、Unicode文字セットを使用するテキストは、複数の抽象文字を使用してユーザーが知覚する文字を表す場合や、単一の抽象文字を使用して複数のユーザーが知覚する文字を表す場合があります。
ワイド文字には別の問題があります。コードユニットのサイズが大きくなるため、すべての文字に使用されるスペースが増えます。シングルバイトコードユニットで適切に表現できるテキストを処理したいが、ワイド文字のシステムを使用する必要がある場合、使用されるメモリの量は、シングルバイトコードユニットの場合よりも多くなります。そのため、ワイド文字は幅が広すぎないことが望まれました。同時に、ワイド文字は、文字セットのすべてのメンバーに一意の値を提供するのに十分な幅である必要があります。
Unicodeには現在、約100,000の抽象文字が含まれています。これには、ほとんどの人が使用するよりも幅の広いワイド文字が必要であることがわかります。結果として、ワイド文字のシステム。コードポイント値を直接格納するために1バイトを超えるコード単位が使用される場合、望ましくないことがわかります。
要約すると、元々、バイト、コードユニット、コードポイント、抽象文字、およびユーザーが認識する文字を区別する必要はありませんでした。ただし、時間の経過とともに、これらの各概念を区別する必要が生じました。
エンコーディング
上記の前は、テキストデータは簡単に保存できました。すべてのユーザーが認識した文字は、コードポイント値を持つ抽象文字に対応していました。256の値で十分な文字が十分にありませんでした。したがって、ユーザーが認識した目的の文字に対応するコードポイント番号をバイトとして直接格納するだけです。その後、ワイド文字では、ユーザーが認識した文字に対応する値が、たとえば16ビットなどのより大きなサイズの整数として直接格納されました。
しかし、Unicodeテキストをこの方法で保存すると、人々が費やすよりも多くのメモリを使用するため(文字ごとに3または4バイト)Unicodeの「エンコーディング」は、コードポイント値を直接保存するのではなく、リバーシブル関数を使用してテキストを保存します。各コードポイントに格納するコードユニット値の数。
たとえば、UTF-8エンコーディングは、最も一般的に使用されるUnicodeコードポイントを取得し、単一の1バイトコードユニットを使用してそれらを表すことができます。あまり一般的ではないコードポイントは、2つの1バイトコードユニットを使用して格納されます。まだあまり一般的ではないコードポイントは、3つまたは4つのコードユニットを使用して格納されます。
これは、一般的なテキストは通常、16ビット幅の文字スキームよりも少ないメモリを使用してUTF-8エンコーディングで格納できることを意味しますが、格納される数値は必ずしも抽象文字のコードポイント値に直接対応するわけではありません。代わりに、どの抽象文字が格納されているかを知る必要がある場合は、格納されているコード単位を「デコード」する必要があります。また、ユーザーが知覚する文字を知る必要がある場合は、抽象文字をさらにユーザーが知覚する文字に変換する必要があります。
さまざまなエンコーディングがあり、それらのエンコーディングを使用してデータを抽象文字に変換するには、正しいデコード方法を知っている必要があります。コードポイント値をコード単位に変換するためにどのエンコーディングが使用されたかがわからない場合、保存された値は事実上無意味です。
エンコーディングの重要な意味は、エンコードされたデータの特定の操作が有効であるか、意味があるかを知る必要があるということです。
たとえば、文字列の「サイズ」を取得したい場合、バイト、コード単位、抽象文字、またはユーザーが認識した文字を数えていますか?std::string::size()
コード単位をカウントします。別のカウントが必要な場合は、別の方法を使用する必要があります。
別の例として、エンコードされた文字列を分割する場合、結果がそのエンコードで引き続き有効であり、データの意味が意図せずに変更されていないように分割しているかどうかを知る必要があります。たとえば、同じコードポイントに属するコードユニット間で分割して、無効なエンコーディングを生成する場合があります。または、ユーザーが認識した文字を表すために組み合わせる必要のあるコードポイント間で分割して、ユーザーが正しくないと見なすデータを生成する場合もあります。
回答
現在char
、wchar_t
コードユニットとのみ見なすことができます。1バイトしかないという事実char
は、2、3、または4バイトを取るコードポイントを表すことを妨げるものではありません。単に2つ、3つ、または4つchar
のを順番に使用する必要があります。これが、UTF-8が機能することを意図した方法です。同様に、wchar_t
UTF-16を表すために2バイトを使用するプラットフォームはwchar_t
、必要に応じて2バイトを続けて使用するだけです。との実際の値は、Unicodeコードポイントを個別に表すものではchar
ありwchar_t
ません。これらは、コードポイントのエンコードから生じるコードユニット値を表します。たとえば、UnicodeコードポイントU + 0400は、UTF-8->で2つのコードユニットにエンコードされます0xD0 0x80
。UnicodeコードポイントU+24B62も同様に、4つのコードユニットとしてエンコードされます0xF0 0xA4 0xAD 0xA2
。
std::string
したがって、UTF-8でエンコードされたデータを保持するために使用できます。
Windowsではmain()
、ASCIIだけでなく、システムchar
エンコーディングが何であれサポートします。残念ながら、Windowsはchar
他のプラットフォームのようにシステムエンコーディングとしてUTF-8をサポートしていないため、cp1252などのレガシーエンコーディングまたはシステムで使用するように構成されているものに制限されます。main()
ただし、 sargc
とパラメータを使用する代わりに、Win32API呼び出しを使用してUTF-16コマンドラインパラメータに直接アクセスすることはできargv
ます。GetCommandLineW()
およびを参照してくださいCommandLineToArgvW
。
wmain()
のargv
パラメータはUnicodeを完全にサポートしています。wchar_t
Windowsに格納されている16ビットコードユニットはUTF-16コードユニットです。Windows APIはUTF-16をネイティブに使用するため、Windowsでの操作は非常に簡単です。wmain()
ただし、は非標準であるため、これに依存することはできません。