C ++文字列(またはchar *)をwstring(またはwchar_t *)に変換


171
string s = "おはよう";
wstring ws = FUNCTION(s, ws);

sの内容をwsにどのように割り当てますか?

グーグルを検索し、いくつかのテクニックを使用しましたが、正確なコンテンツを割り当てることができません。コンテンツが歪んでいる。


7
strings> 8ビット文字は受け入れないと思います。すでにUTF-8でエンコードされていますか?
kennytm 2010

3
"おはよう"システムでエンコードされた文字列を作成する場合、システムのエンコードは何ですか?
sbi

MSVCはそれを受け入れ、マルチバイトエンコーディング、おそらくUTF-8にするでしょう。
Potatoswatter 2010

1
@Potatoswatter:MSVCはデフォルトでANYTHINGにUTF-8を使用しません。あなたはそれらの文字を入力した場合、それはにファイルを変換するためにエンコードされ要求し、コードページ1252にデフォルト設定
ダックMooing

2
@Samir:ファイルのエンコーディングは何ですか?その文字列をファイルの先頭に移動して、その部分の16進ダンプを表示できますか?おそらくそれからそれを特定することができます。
Mooing Duck 2013

回答:


239

あなたの例の入力文字列(おはよう)がUTF-8でエンコードされていると想定します(見た目ではそうではありませんが、この説明のためであると想定しましょう:-))Unicode文字列の表現興味があれば、標準ライブラリ(C ++ 11以降)だけで問題を完全に解決できます。

TL; DRバージョン:

#include <locale>
#include <codecvt>
#include <string>

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string narrow = converter.to_bytes(wide_utf16_source_string);
std::wstring wide = converter.from_bytes(narrow_utf8_source_string);

より長いオンラインでコンパイルおよび実行可能な例:

(それらはすべて同じ例を示しています。冗長性のために多くあります...)

注意(古い)

コメントで指摘され、https://stackoverflow.com/a/17106065/6345で説明されているように、標準ライブラリを使用してUTF-8とUTF-16の間で変換すると、異なるプラットフォームでの結果に予期しない違いが生じる場合があります。より良い変換std::codecvt_utf8については、http://en.cppreference.com/w/cpp/locale/codecvt_utf8で説明されているように考慮してください

注意(新規)

codecvtヘッダーはC ++ 17で廃止されたため、この回答で提示された解決策についての懸念が提起されました。ただし、C ++標準委員会はhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.htmlと言って重要な声明を追加しました

このライブラリコンポーネントは、適切な代替品が標準化されるまで、とともに、Annex Dに廃棄する必要があります。

したがって、近い将来、codecvtこの回答のソリューションは安全で移植可能です。


2
VSファイルをどのエンコーディングで保存するかを確認してください
Johann Gerell

9
これはC ++ 11のみであることに注意してください!
bk138 2014年

1
minGW(gcc / g ++ 4.8.1および-std = c ++ 11)では、codecvtヘッダーは存在しません。代わりはありますか?
ブライアンジャック

1
std::codecvt_utf8初心者向けの例を提供して
いただけ

15
<codecvt>C ++ 17以降は非推奨であることに注意してください。
タンブル

47
int StringToWString(std::wstring &ws, const std::string &s)
{
    std::wstring wsTmp(s.begin(), s.end());

    ws = wsTmp;

    return 0;
}

93
これは、すべての文字が1バイト、つまりASCIIまたはISO-8859-1の場合にのみ機能します。UTF-8を含め、マルチバイトのすべてが無残に失敗します。質問には明らかにマルチバイト文字が含まれています。
Mark Ransom 2013

28
この答えは明らかに不十分であり、ナロー文字をワイド文字にそのままコピーするだけです。マルチバイトまたはutf8エンコードされた文字列からutf16 wstringに適切に移行する方法については、他の回答、特にJohann Gerellの回答を参照してください。
DLRdave 2013年

10
この回答は危険であり、ASCII以外のシステムでは機能しなくなる可能性があります。つまり、アラビア語のファイル名はこのハックによって壊されます。
スティーブン

9
この回答は、質問の本文のニュアンスを無視して、質問のタイトルに焦点を当てている場合に役立ちます。これは、Googleから私をここに連れてきたものです。現状のままで、質問のタイトルは非常に誤解を招くものであり、質問されている本当の質問を反映するように変更する必要があります
Anne Quinn

3
これは7ビットASCII文字でのみ機能します。latin1の場合、charが符号なしとして構成されている場合にのみ機能します。char型が署名されている場合(ほとんどの場合)、127を超える文字は誤った結果になります。
huyc 2016年

32

あなたの質問は不充分です。厳密には、その例は構文エラーです。しかし、std::mbstowcsおそらくあなたが探しているものです。

これはCライブラリ関数であり、バッファで動作しますが、TBohne(旧Mooing Duck)の厚意による、使いやすいイディオムを次に示します。

std::wstring ws(s.size(), L' '); // Overestimate number of code points.
ws.resize(std::mbstowcs(&ws[0], s.c_str(), s.size())); // Shrink to fit.

1
string s = "おはよう"; wchar_t * buf = new wchar_t [s.size()]; size_t num_chars = mbstowcs(buf、s.c_str()、s.size()); wstring ws(buf、num_chars); // ws = distorted
Samir

1
@Samir:ランタイムエンコーディングがコンパイル時エンコーディングと同じであることを確認する必要があります。setlocaleコンパイラフラグを調整する必要があるかもしれません。私はWindowsを使用していないのでわかりませんが、これが一般的な機能ではない理由です。可能であれば、他の回答を検討してください。
Potatoswatter 2010

1
std::string ws(s.size()); ws.resize(mbstowcs(&ws[0], s.c_str(), s.size());RAII FTW
Mooing Duck 2013

2
@WaffleSouffleそれは時代遅れです。2011年以降、連続した実装が必要であり、実装はそれ以前にそのようなトリックをやめました。
Potatoswatter、2014

1
そしてmingwのような一部の環境にはまだcodecvtヘッダーがないため、以前の「より良い」ソリューションの一部は機能しません。つまり、2014年12月の時点でも、この問題はmingwで良い解決策がありません
Brian Jack

18

Windows APIのみ、誰かがそれを必要とする場合のためのC ++ 11実装前:

#include <stdexcept>
#include <vector>
#include <windows.h>

using std::runtime_error;
using std::string;
using std::vector;
using std::wstring;

wstring utf8toUtf16(const string & str)
{
   if (str.empty())
      return wstring();

   size_t charsNeeded = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), NULL, 0);
   if (charsNeeded == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   vector<wchar_t> buffer(charsNeeded);
   int charsConverted = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), &buffer[0], buffer.size());
   if (charsConverted == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   return wstring(&buffer[0], charsConverted);
}

あなたはそれを最適化することができます。を使用して文字列の二重コピーを行う必要はありませんvector。文字列の文字を予約してwstring strW(charsNeeded + 1);、変換用のバッファとして使用します&strW[0]。最後に、変換して最後のnullが存在することを確認しますstrW[charsNeeded] = 0;
c00000fd

1
@ c00000fd、私が知る限り、std :: basic_string内部バッファーは、C ++ 11標準以降のみ継続する必要があります。私のコードは投稿の上部に記載されているように、C ++ 11より前です。したがって、&strW [0]コードは標準に準拠しておらず、実行時に合法的にクラッシュする可能性があります。
Alex Che

13

あなたが使用している場合のWindows / Visual Studioの、あなたが使用することができwstringのに文字列を変換する必要が:

#include <AtlBase.h>
#include <atlconv.h>
...
string s = "some string";
CA2W ca2w(s.c_str());
wstring w = ca2w;
printf("%s = %ls", s.c_str(), w.c_str());

wstringをstringに変換する同じ手順(コードページを指定する必要がある場合もあります):

#include <AtlBase.h>
#include <atlconv.h>
...
wstring w = L"some wstring";
CW2A cw2a(w.c_str());
string s = cw2a;
printf("%s = %ls", s.c_str(), w.c_str());

コードページを指定したり、UTF8を指定したりすることもできます(JNI / Javaを操作する場合は、これは非常に便利です)。標準の方法UTF8にはstd :: wstringの変換ははstd ::文字列は、この回答でしたさ

// 
// using ATL
CA2W ca2w(str, CP_UTF8);

// 
// or the standard way taken from the answer above
#include <codecvt>
#include <string>

// convert UTF-8 string to wstring
std::wstring utf8_to_wstring (const std::string& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.from_bytes(str);
}

// convert wstring to UTF-8 string
std::string wstring_to_utf8 (const std::wstring& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.to_bytes(str);
}

コードページについて詳しく知りたい場合は、Joel on Software:The Absolute Minimum Every Software Developer Absolutely、Positively Positive Known知るUnicode and Character Setsに関する興味深い記事がありますます。

これらのCA2W(AnsiをWide = unicodeに変換)マクロは、サンプルが含まれているATLおよびMFC文字列変換マクロの一部です。

場合によっては、セキュリティ警告#4995を無効にする必要があります。他の回避策はわかりません(VS2012でWindowsXp用にコンパイルしたときに発生します)。

#pragma warning(push)
#pragma warning(disable: 4995)
#include <AtlBase.h>
#include <atlconv.h>
#pragma warning(pop)

編集: まあ、この記事によると、Joelによる記事は「面白い間は、実際の技術的な詳細はかなり軽い」のようです。記事:すべてのプログラマーが、テキストを処理するためのエンコーディングと文字セットについて確実に知っておくべきこと


申し訳ありませんが、私は英語が母国語ではありません。必要に応じて編集してください。
lmiguelmh 2014年

ダウンボーターはどうなっていますか?答えの何が問題になっていますか?
lmiguelmh 2015年

おそらくそれが移植性のないコードを促進するという事実。
Pavel Minaev 2015

はい、そのため、これはWindows / Visual Studioでのみ機能すると述べました。しかし、少なくとも、このソリューションは、この1正しいこと、およびない:char* str = "hello worlddd"; wstring wstr (str, str+strlen(str));
lmiguelmh

追記:CA2WはATLの名前空間の下にあります。(ATL :: CA2W)
Val

12

ここ組み合わせへの道だstringwstringとの混合文字列定数はwstring。使用wstringstreamクラスをます。

これはマルチバイト文字エンコーディングでは機能しません。これは、型の安全性を破棄し、std :: stringから7ビット文字をstd:wstringの各文字の下位7ビットに拡張する、おかしな方法です。これは、7ビットのASCII文字列があり、ワイド文字列を必要とするAPIを呼び出す必要がある場合にのみ役立ちます。

#include <sstream>

std::string narrow = "narrow";
std::wstring wide = L"wide";

std::wstringstream cls;
cls << " abc " << narrow.c_str() << L" def " << wide.c_str();
std::wstring total= cls.str();

答えは興味深いようです。少し説明してもらえますか?これはマルチバイトエンコーディングで機能しますか?その理由/方法は?
wh1t3cat1k 2015年

エンコーディングスキームは、ストレージクラスに直交しています。string1バイト文字をwstring格納し、2 バイト文字を格納します。utf8のようなものは、マルチバイト文字を一連の1バイト値として、つまりに格納しstringます。文字列クラスはエンコードに役立ちません。私はc ++でクラスをエンコードすることの専門家ではありません。
Mark Lakata、2015年

2
これがどれほど短く単純であるかを考えると、これが最良の答えではない理由は何ですか?それがカバーしないケースはありますか?

@MarkLakata、最初のコメントへの回答を読みましたが、まだわかりません。マルチバイト文字でも機能しますか?つまり、この回答と同じ落とし穴に陥りやすいのではないでしょうか。
Marc.2377

@ Marc.2377これはマルチバイト文字エンコーディングでは機能しません。これは、タイプセーフを破棄し、7ビット文字std::stringをの各文字の下位7ビットに拡張するというおかしな方法ですstd:wstring。これは、7ビットのASCII文字列があり、ワイド文字列を必要とするAPIを呼び出す必要がある場合にのみ役立ちます。より洗練されたものが必要な場合は、stackoverflow.com / a / 8969776/3258851をご覧ください。
Mark Lakata、

11

からchar*wstring

char* str = "hello worlddd";
wstring wstr (str, str+strlen(str));

からstringwstring

string str = "hello worlddd";
wstring wstr (str.begin(), str.end());

これは、変換される文字列にASCII文字のみが含まれている場合にのみ機能することに注意してください。


7
これは、エンコーディングがWindows-1252である場合にのみ機能するため、問題の文字を保持することもできません。
Mooing Duck 2013

3
これは、ASCIIを扱っていることがわかっている場合、エラーを起こしにくい方法です。これは、アプリを新しいAPIに移植する際の顕著なユースケースです。
Sid Sarasvati、2014

これは方法ではありません。Visual Studioを使用してatlconv.hいる場合は、を使用する必要があります。他の回答を確認してください。
lmiguelmh 2014年


5

それのこの変種は、実際の生活の中で私のお気に入りです。入力が有効な UTF-8の場合、入力をそれぞれのに変換しますwstring。入力が破損している場合wstringは、1バイトから構成されます。これは、入力データの品質について本当に確信が持てない場合に非常に役立ちます。

std::wstring convert(const std::string& input)
{
    try
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.from_bytes(input);
    }
    catch(std::range_error& e)
    {
        size_t length = input.length();
        std::wstring result;
        result.reserve(length);
        for(size_t i = 0; i < length; i++)
        {
            result.push_back(input[i] & 0xFF);
        }
        return result;
    }
}

1
私はあなたの答えに基づいてこの質問を開始しましたstackoverflow.com/questions/49669048/…親切に見て
いただけ

2

QTがあり、関数やものを実装するのに時間がかかる場合は、

std :: string str; QString(str).toStdWString()


ほぼ、ただしQStringQStringコンストラクタは何らかの理由で文字列を受け入れることができないため、で始める必要があります。
bobsbeenjamin


これはいいね。また、.c_str()を使用して、QStringにコンストラクター内の文字列を受け入れさせることができます。
miep

1

メソッドs2wsはうまく機能します。願っています。

std::wstring s2ws(const std::string& s) {
    std::string curLocale = setlocale(LC_ALL, ""); 
    const char* _Source = s.c_str();
    size_t _Dsize = mbstowcs(NULL, _Source, 0) + 1;
    wchar_t *_Dest = new wchar_t[_Dsize];
    wmemset(_Dest, 0, _Dsize);
    mbstowcs(_Dest,_Source,_Dsize);
    std::wstring result = _Dest;
    delete []_Dest;
    setlocale(LC_ALL, curLocale.c_str());
    return result;
}

6
安全でない方法で動的メモリを割り当ててから、バッファから文字列にデータをコピーするこれらすべての答えとは何ですか?安全でない仲買人を誰も排除しないのはなぜですか?
Mooing Duck

hahakubile、ws2sの同様のものであなたを助けてくれますか?
クリスティアン2016年

1

私自身のテスト(Windows 8、vs2010)に基づいて、mbstowcsは実際に元の文字列を損傷する可能性があり、ANSIコードページでのみ機能します。MultiByteToWideChar / WideCharToMultiByteも文字列の破損を引き起こす可能性がある場合-しかし、知らない文字を「?」で置き換える傾向があります。クエスチョンマークですが、mbstowcsは、不明な文字が検出され、その時点で文字列をカットすると停止する傾向があります。(私はフィンランド語のウィンドウでベトナム文字をテストしました)。

そのため、アナログのansi C関数よりもMulti * -windows api関数を優先してください。

また、あるコードページから別のコードページに文字列をエンコードする最も短い方法は、MultiByteToWideChar / WideCharToMultiByte API関数呼び出しではなく、アナログのATLマクロW2A / A2Wを使用していることです。

したがって、上記のアナログ機能は次のように聞こえます。

wstring utf8toUtf16(const string & str)
{
   USES_CONVERSION;
   _acp = CP_UTF8;
   return A2W( str.c_str() );
}

_acpはUSES_CONVERSIONマクロで宣言されています。

または、古いデータを新しいデータに変換するときによく見落とす機能:

string ansi2utf8( const string& s )
{
   USES_CONVERSION;
   _acp = CP_ACP;
   wchar_t* pw = A2W( s.c_str() );

   _acp = CP_UTF8;
   return W2A( pw );
}

ただし、これらのマクロはスタックを多用していることに注意してください。W2AまたはA2Wマクロを使用した後は、forループや同じ関数の再帰ループを使用しないでください。


1

文字列からwstring

std::wstring Str2Wstr(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

wstringからStringへ

std::string Wstr2Str(const std::wstring& wstr)
{
    typedef std::codecvt_utf8<wchar_t> convert_typeX;
    std::wstring_convert<convert_typeX, wchar_t> converterX;
    return converterX.to_bytes(wstr);
}

1
このStr2Wstrには0の終了に関する問題があります。生成されたwstringを「+」を介して連結することはできなくなりました(wstring s3 = s1 + s2のように)。私はすぐにこの問題を解決する答えを投稿します。最初にメモリリークのテストを行う必要があります。
thewhiteambit

-2

string s = "おはよう"; エラーです。

wstringを直接使用する必要があります。

wstring ws = L"おはよう";

1
それもうまくいきません。これらの非BMP文字をCエスケープシーケンスに変換する必要があります。
Dave Van den Eynde

3
@Dave:コンパイラがソースファイルのユニコードをサポートし、過去10年間のすべてがサポートしている場合(Visual Studio、GCCなど)に機能します
Thomas Bonini

こんにちは、デフォルトのシステムエンコーディング(たとえば、デフォルトのシステムエンコーディングとしてアラビア語を使用している場合があります)に関係なく、L "おはよう"のソースコードファイルのエンコーディングはどのように機能しますか?UTF-16にする必要がありますか、それとも.cppファイルエンコーディングのBOMなしでUTF-8を使用できますか
Afriza N. Arief 2010

2
@afriza:コンパイルがそれをサポートしている限り、それは本当に問題ではありません
Thomas Bonini

2
エラーではありません。「狭い」文字列内の拡張文字は、マルチバイトシーケンスにマップするように定義されています。コンパイラは、OSがサポートしている限りサポートする必要があります。
Potatoswatter 2013年

-2

このコードを使用して、文字列をwstringに変換します

std::wstring string2wString(const std::string& s){
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

int main(){
    std::wstring str="your string";
    std::wstring wStr=string2wString(str);
    return 0;
}

3
質問にはWindowsについての言及はなく、この回答はWindowsのみであることに注意してください。
Johann Gerell 2015

CP_ACP間違いなく間違いです。突然、実行中のスレッドの環境状態がコードの動作に影響を与えます。お勧めできません。変換で固定文字エンコードを指定します。(エラーの処理を検討してください。)
IInspectable 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.