std::string
との違いがわかりませんstd::wstring
。wstring
Unicode文字などのワイド文字をサポートしていることは知っています。次の質問があります。
- いつ使い替えるべきです
std::wstring
かstd::string
? std::string
特殊文字を含むASCII文字セット全体を保持できますか?std::wstring
すべての一般的なC++コンパイラでサポートされていますか?- 正確には「ワイド文字」とは何ですか?
string
?wstring
?std::string
は、およびにbasic_string
テンプレート化されています。char
std::wstring
wchar_t
char
対。wchar_t
char
文字、通常は8ビット文字を保持することになっています。
wchar_t
はワイド文字を保持することになっているため、注意が必要です。Linuxではawchar_t
は4バイトですが、Windowsでは2バイトです。
問題は、どちらchar
もwchar_t
ユニコードに直接結び付けられていないことです。
LinuxOSを見てみましょう。私のUbuntuシステムはすでにUnicodeに対応しています。char文字列を操作する場合、 UTF-8(つまり、Unicode文字列のchars)でネイティブにエンコードされます。次のコード:
#include <cstring>
#include <iostream>
int main()
{
const char text[] = "olé";
std::cout << "sizeof(char) : " << sizeof(char) << "\n";
std::cout << "text : " << text << "\n";
std::cout << "sizeof(text) : " << sizeof(text) << "\n";
std::cout << "strlen(text) : " << strlen(text) << "\n";
std::cout << "text(ordinals) :";
for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
{
unsigned char c = static_cast<unsigned_char>(text[i]);
std::cout << " " << static_cast<unsigned int>(c);
}
std::cout << "\n\n";
// - - -
const wchar_t wtext[] = L"olé" ;
std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << "\n";
//std::cout << "wtext : " << wtext << "\n"; <- error
std::cout << "wtext : UNABLE TO CONVERT NATIVELY." << "\n";
std::wcout << L"wtext : " << wtext << "\n";
std::cout << "sizeof(wtext) : " << sizeof(wtext) << "\n";
std::cout << "wcslen(wtext) : " << wcslen(wtext) << "\n";
std::cout << "wtext(ordinals) :";
for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
{
unsigned short wc = static_cast<unsigned short>(wtext[i]);
std::cout << " " << static_cast<unsigned int>(wc);
}
std::cout << "\n\n";
}
次のテキストを出力します。
sizeof(char) : 1
text : olé
sizeof(text) : 5
strlen(text) : 4
text(ordinals) : 111 108 195 169
sizeof(wchar_t) : 4
wtext : UNABLE TO CONVERT NATIVELY.
wtext : ol�
sizeof(wtext) : 16
wcslen(wtext) : 3
wtext(ordinals) : 111 108 233
の「olé」テキストchar
は、実際には110、108、195、169の4つの文字で構成されています(末尾のゼロは数えません)。wchar_t
(演習としてコードを学習させます)
したがって、char
Linuxで作業する場合は、通常、知らないうちにUnicodeを使用することになります。そして、でstd::string
動作するchar
ように、std::string
すでにユニコード対応です。
std::string
C文字列APIと同様に、「olé」文字列は3文字ではなく4文字であると見なされることに注意してください。したがって、UTF-8では文字の組み合わせが禁止されているため、Unicode文字を切り捨てたり再生したりする場合は注意が必要です。
Windowsでは、これは少し異なります。Win32は、Unicodeが登場する前に、世界中で作成されchar
たさまざまな文字セット/コードページで動作する多くのアプリケーションをサポートする必要がありました。
したがって、彼らの解決策は興味深いものでした。アプリケーションがで動作する場合char
、char文字列はマシンのローカルcharset / codepageを使用してGUIラベルにエンコード/印刷/表示されますが、これは長い間UTF-8ではありませんでした。たとえば、「olé」はフランス語にローカライズされたWindowsでは「olé」になりますが、キリル文字にローカライズされたWindowsでは「olé」になります(Windows-1251を使用している場合は「olй」 )。したがって、「履歴アプリ」は通常、同じように機能します。
Unicodeベースのアプリケーションの場合、Windowswchar_t
は2バイト幅のを使用し、 UTF-16でエンコードされます。UTF-16は2バイト文字でエンコードされたUnicodeです(または、少なくとも、サロゲートペアがないUCS-2としたがって、BMP外の文字(> = 64K))。
を使用するアプリケーションchar
は「マルチバイト」(各グリフが1つ以上で構成されているためchar
)と呼ばれ、使用しているアプリケーションwchar_t
は「ワイド文字」(各グリフが1つまたは2つで構成されているため)と呼ばれますwchar_t
。詳細については、 MultiByteToWideCharおよびWideCharToMultiByteWin32変換APIを参照してください。
したがって、Windowsで作業している場合は、 ( GTKやQTなどのようにそれを隠すフレームワークを使用しない限り)ひどく使用したいと思うでしょう。事実、Windowsは舞台裏で文字列を処理するため、履歴アプリケーションでさえ、 API (Win32 GUIでラベルを設定するための低レベルAPI関数)を使用すると文字列が変換されます。wchar_t
wchar_t
char
wchar_t
SetWindowText()
UTF-32は1文字あたり4バイトであるため、UTF-8テキストとUTF-16テキストが常にUTF-32テキストよりも少ないか同じ量のメモリを使用する場合(通常は少ない)、追加することはあまりありません。 )。
メモリの問題がある場合は、ほとんどの西洋言語よりも、UTF-8テキストが同じUTF-16テキストよりも少ないメモリを使用することを知っておく必要があります。
それでも、他の言語(中国語、日本語など)の場合、使用されるメモリは同じか、UTF-16よりもUTF-8の方がわずかに大きくなります。
全体として、UTF-16はほとんどの場合1文字あたり2バイト、場合によっては4バイトを使用します(ある種の難解言語グリフ(クリンゴン?エルフ?)を扱っている場合を除く)が、UTF-8は1〜4バイトを使用します。
詳細については、 https://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16を参照してください。
std::stringよりもstd::wstringを使用する必要があるのはいつですか?
Linuxでは?ほとんどは決してない (§)。Windowsでは?ほとんどいつも (§)。クロスプラットフォームコードについて?ツールキットによって異なります...
(§):ツールキット/フレームワークを使用しない限り、別の言い方をします
std::string
特殊文字を含むすべてのASCII文字セットを保持できますか?
注意:Astd::string
は、「バイナリ」バッファを保持するのに適していますが、astd::wstring
はそうではありません。
Linuxでは?はい。Windowsでは?Windowsユーザーの現在のロケールで使用できる特殊文字のみ。
編集(Johann Gerellからのコメントの後):すべてのベースの文字列(それぞれが0から255までの数値)を処理するには
、astd::string
で十分です。だが:char
char
char
sはASCIIではありません。char
0から127までは正しく保持されますchar
エンコード(Unicode、非Unicodeなど)に応じて意味がありますが、UTF-8でエンコードされている限り、すべてのUnicodeグリフを保持できます。std::wstring
ほとんどすべての一般的なC++コンパイラでサポートされていますか?
ほとんどの場合、Windowsに移植されたGCCベースのコンパイラを除きます。これは私のg++4.3.2(Linuxの場合)で動作し、Visual C++6以降はWin32でUnicodeAPIを使用していました。
正確にワイド文字とは何ですか?
C / C ++では、wchar_t
単純な文字タイプよりも大きい文字タイプが記述されていchar
ます。これは、インデックス(Unicodeグリフなど)が255(または127、場合によっては...)より大きい文字を内部に配置するために使用されることになっています。
std::wstring
インターフェイスで必要な場合を除き、Windows またはその他の場所では避けることをお勧めします。
私の見解は、私が共著者であるhttp://utf8everywhere.orgにまとめられています。
主に UI アプリケーションなど、アプリケーションが API 呼び出し中心でない限り、Unicode 文字列を std::string に格納し、UTF-8 でエンコードして、API 呼び出しの近くで変換を実行することをお勧めします。この記事で概説されている利点は、特に複雑なアプリケーションでは、変換の明らかな煩わしさを上回ります。これは、マルチプラットフォームおよびライブラリ開発の場合に二重に当てはまります。
そして今、あなたの質問に答えます:
したがって、ここにいるすべての読者は、事実、状況について明確に理解している必要があります。そうでない場合は、paercebal の非常に包括的な回答を読む必要があります[ところで: ありがとう!]。
私の実用的な結論は驚くほど単純です。C++ (および STL) の「文字エンコーディング」はすべて、実質的に壊れていて役に立たないということです。マイクロソフトのせいにするかどうかに関係なく、とにかく役に立ちません。
私の解決策は、詳細な調査、多くの欲求不満、およびその結果としての経験の結果、次のとおりです。
エンコーディングと変換については自分で責任を負う必要があることを受け入れてください(そして、その多くはかなり些細なことであることがわかります)
UTF-8 でエンコードされた文字列には std::string を使用します (単にtypedef std::string UTF8String
)
そのような UTF8String オブジェクトはただの馬鹿げた、しかし安価なコンテナであることを受け入れてください。その中の文字に直接アクセスしたり操作したりしないでください (検索、置換などは行わないでください)。可能ですが、マルチバイト文字列用のテキスト操作アルゴリズムを書くのに時間を無駄にしたくありません! 他の人がすでにそのような愚かなことをしたとしても、それをしないでください! なるがままに!(まあ、それが理にかなっているシナリオがあります...それらにはICUライブラリを使用してください)。
UCS-2 でエンコードされた文字列には std::wstring を使用します ( typedef std::wstring UCS2String
) - これは妥協であり、WIN32 API が導入した混乱への譲歩です)。UCS-2 は私たちのほとんどにとって十分です (詳細は後で...)。
文字単位のアクセスが必要な場合 (読み取り、操作など) はいつでも UCS2String インスタンスを使用します。文字ベースの処理は、NON-multibyte-representation で行う必要があります。シンプル、高速、簡単です。
UTF-8 と UCS-2 の間で相互に変換するための 2 つのユーティリティ関数を追加します。
UCS2String ConvertToUCS2( const UTF8String &str );
UTF8String ConvertToUTF8( const UCS2String &str );
変換は簡単です。Google がここで役立つはずです...
それでおしまい。メモリが貴重な場合、およびすべての UTF-8 I/O に対して UTF8String を使用します。文字列を解析および/または操作する必要がある場合は、どこでも UCS2String を使用します。これら 2 つの表現はいつでも変換できます。
代替案と改善
& からシングルバイト文字エンコーディング (ISO-8859-1 など) への変換は、単純な変換テーブル (たとえばconst wchar_t tt_iso88951[256] = {0,1,2,...};
、UCS2 から & への変換用の適切なコード) の助けを借りて実現できます。
UCS-2 では不十分な場合は、UCS-4 に切り替えます ( typedef std::basic_string<uint32_t> UCS2String
)
ICU または他の Unicode ライブラリ?
文字列にワイド文字を格納したい場合。wide
実装によって異なります。Visual C ++は、正しく覚えていればデフォルトで16ビットになりますが、GCCはターゲットに応じてデフォルトになります。ここでは32ビット長です。wchar_t(ワイド文字タイプ)はUnicodeとは関係がないことに注意してください。実装がそのロケールでサポートする最大の文字セットのすべてのメンバーを、少なくともcharまで格納できることが保証されているだけです。エンコーディングを使用するためにUnicode文字列をうまく保存することもできます。ただし、ユニコードコードポイントの意味は理解できません。それでstd::string
utf-8
str.size()
文字列内の論理文字の量はわかりませんが、その文字列/wstringに格納されているcharまたはwchar_t要素の量だけがわかります。そのため、gtk / glib C ++ラッパーの人々は、Glib::ustring
utf-8を処理できるクラスを開発しました。
wchar_tの長さが32ビットの場合、Unicodeエンコーディングとして使用でき、固定(utf-32は固定長)エンコーディングを使用してUnicode文字列をutf-32
格納および処理できます。これは、wstringのs.size()
関数が適切な量のwchar_t要素と論理文字を返すことを意味します。
std::string を頻繁に使用して、まったく問題なくutf-8文字を保持します。utf-8 をネイティブ文字列型として使用する API とやり取りする場合にも、これを行うことを心からお勧めします。
たとえば、コードを Tcl インタープリターとやり取りするときに utf-8 を使用します。
主な注意点は、std::string の長さであり、もはや文字列の文字数ではありません。
良い質問です!データをファイルに保存したり、ネットワーク経由でデータを転送したりするためのDATA ENCODING (場合によってはCHARSETも関与) はMEMORY EXPRESSION MECHANISMだと思うので、この質問に次のように答えます。
1. std::string よりも std::wstring を使用する必要があるのはいつですか?
プログラミング プラットフォームまたは API 関数が 1 バイトのものであり、Windows の .REG ファイルまたはネットワークの 2 バイト ストリームから読み取るなど、一部の Unicode データを処理または解析する場合は、std::wstring 変数を簡単に宣言する必要があります。それらを処理します。例: wstring ws=L"中国a"(6 オクテット メモリ: 0x4E2D 0x56FD 0x0061)、ws[0] を使用して文字「中」を取得し、ws[1] を使用して文字「国」を取得し、ws[2] を使用して文字「a」などを取得します。
2. std::string は、特殊文字を含む ASCII 文字セット全体を保持できますか?
はい。ただし、注意: アメリカの ASCII は、各 0x00~0xFF オクテットが「123abc&*_&」などの印刷可能なテキストを含む 1 つの文字を表すことを意味します。エディターや端末を混乱させないようにします。また、他のいくつかの国では、独自の「ASCII」文字セットを拡張しています。たとえば、中国語では、2 オクテットを使用して 1 文字を表します。
3. std::wstring は、一般的なすべての C++ コンパイラでサポートされていますか?
たぶん、またはほとんど。私が使用したもの: VC++6 および GCC 3.3、はい
4. 「ワイド文字」とは正確には何ですか?
ワイド文字は、ほとんどの場合、すべての国の文字を保持するために 2 オクテットまたは 4 オクテットを使用することを示します。2オクテットのUCS2が代表的なサンプルで、さらに例えば英語の「a」では、そのメモリは0x0061の2オクテットです(対ASCIIの「a」のメモリは1オクテットの0x61)。
256 文字だけでは満足できないアプリケーションには、ワイド文字 (8 ビットを超える) または UTF-8 などの可変長エンコーディング (C++ 用語ではマルチバイト エンコーディング) を使用するオプションがあります。一般に、ワイド文字は可変長エンコーディングよりも多くのスペースを必要としますが、処理は高速です。大量のテキストを処理する多言語アプリケーションは、通常、テキストを処理するときにワイド文字を使用しますが、ディスクに保存するときに UTF-8 に変換します。
string
aと aの唯一の違いwstring
は、格納する文字のデータ型です。char
文字列には、サイズが少なくとも 8 ビットであることが保証されている s が格納されるため、ASCII、ISO-8859-15、または UTF-8 テキストなどの処理に文字列を使用できます。標準は、文字セットやエンコーディングについて何も述べていません。
実際、すべてのコンパイラは、最初の 128 文字が ASCII に対応する文字セットを使用しています。これは、UTF-8 エンコーディングを使用するコンパイラにも当てはまります。UTF-8 またはその他の可変長エンコーディングで文字列を使用する場合に注意すべき重要な点は、インデックスと長さが文字ではなくバイト単位で測定されることです。
wstring のデータ型は でwchar_t
、そのサイズは標準では定義されていませんが、少なくとも char と同じ大きさでなければならず、通常は 16 ビットまたは 32 ビットでなければなりません。wstring は、実装定義のワイド文字エンコーディングでテキストを処理するために使用できます。エンコーディングは標準で定義されていないため、文字列と wstring の間の変換は簡単ではありません。wstring が固定長エンコーディングを持つと仮定することもできません。
多言語サポートが必要ない場合は、通常の文字列のみを使用しても問題ないかもしれません。一方、グラフィカル アプリケーションを作成している場合は、API がワイド文字のみをサポートすることがよくあります。次に、テキストを処理するときに同じワイド文字を使用したいと思うでしょう。UTF-16 は可変長エンコーディングであるlength()
ため、文字数を返すとは想定できないことに注意してください。API が UCS-2 などの固定長エンコーディングを使用すると、処理が容易になります。ワイド文字と UTF-8 の間の変換は、移植可能な方法で行うのは困難ですが、繰り返しますが、ユーザー インターフェイス API はおそらく変換をサポートしています。
1) Greg が述べたように、wstring は国際化に役立ちます。それは、英語以外の言語で製品をリリースするときです。
4) ワイド文字については、こちらを ご覧ください http://en.wikipedia.org/wiki/Wide_character
ワイド文字を使用してはいけないのはいつですか?
1990年より前にコードを書いているとき。
明らかに、私はひっくり返っていますが、実際には、21世紀になりました。127文字では十分ではなくなってから長い年月が経ちました。はい、UTF8を使用できますが、なぜ頭痛の種に悩まされるのでしょうか。