web-dev-qa-db-ja.com

wstringを文字列に変換する方法

問題は、wstringを文字列に変換する方法です。

私は次の例があります:

#include <string>
#include <iostream>

int main()
{
    std::wstring ws = L"Hello";
    std::string s( ws.begin(), ws.end() );

  //std::cout <<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;
    std::cout <<"std::string =     "<<s<<std::endl;
}

コメントアウトされた行の出力は次のとおりです。

std::string =     Hello
std::wstring =    Hello
std::string =     Hello

しかしなしでのみです:

std::wstring =    Hello

例で何か問題がありますか?上記のように変換できますか?

EDIT

新しい例(いくつかの答えを考慮に入れる)は

#include <string>
#include <iostream>
#include <sstream>
#include <locale>

int main()
{
    setlocale(LC_CTYPE, "");

    const std::wstring ws = L"Hello";
    const std::string s( ws.begin(), ws.end() );

    std::cout<<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;

    std::stringstream ss;
    ss << ws.c_str();
    std::cout<<"std::stringstream =     "<<ss.str()<<std::endl;
}

出力は以下のとおりです。

std::string =     Hello
std::wstring =    Hello
std::stringstream =     0x860283c

したがって、stringstreamを使用してwstringをstringに変換することはできません。

181
BЈовић

これは他の提案に基づいて解決されたソリューションです:

#include <string>
#include <iostream>
#include <clocale>
#include <locale>
#include <vector>

int main() {
  std::setlocale(LC_ALL, "");
  const std::wstring ws = L"ħëłlö";
  const std::locale locale("");
  typedef std::codecvt<wchar_t, char, std::mbstate_t> converter_type;
  const converter_type& converter = std::use_facet<converter_type>(locale);
  std::vector<char> to(ws.length() * converter.max_length());
  std::mbstate_t state;
  const wchar_t* from_next;
  char* to_next;
  const converter_type::result result = converter.out(state, ws.data(), ws.data() + ws.length(), from_next, &to[0], &to[0] + to.size(), to_next);
  if (result == converter_type::ok or result == converter_type::noconv) {
    const std::string s(&to[0], to_next);
    std::cout <<"std::string =     "<<s<<std::endl;
  }
}

これは通常Linuxでは機能しますが、Windowsでは問題を引き起こします。

29
Philipp

Cubbiがコメントの1つで指摘したように、std::wstring_convert(C++ 11)はきちんとした簡単な解決策を提供します(#include<locale><codecvt>が必要です):

std::wstring string_to_convert;

//setup converter
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;

//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str = converter.to_bytes( string_to_convert );

私がこれに遭遇する前に、私はwcstombsと面倒なメモリの割り当て/割り当て解除の組み合わせを使用していました。

http://en.cppreference.com/w/cpp/locale/wstring_convert

更新(2013.11.28)

1人のライナーはそのように述べることができます(あなたのコメントをありがとうGuss):

std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some string");

ラッパー関数はそのように言うことができます:(コメントありがとうArmanSchwarz)

std::wstring s2ws(const std::string& str)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.from_bytes(str);
}

std::string ws2s(const std::wstring& wstr)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.to_bytes(wstr);
}

注:string/wstringを参照として、またはリテラルとして関数に渡すべきかどうかについては、いくつかの議論があります(C++ 11およびコンパイラの更新による)。実行する人に決定を任せますが、知る価値があります。

注意:上記のコードではstd::codecvt_utf8を使用していますが、UTF-8を使用していない場合は、使用している適切なエンコーディングに変更する必要があります。

http://en.cppreference.com/w/cpp/header/codecvt

272
dk123

からの解決策: http://forums.devshed.com/c-programming-42/wstring-to-string-444006.html

std::wstring wide( L"Wide" ); 
std::string str( wide.begin(), wide.end() );

// Will print no problemo!
std::cout << str << std::endl;

ここではno文字セット変換が行われていないことに注意してください。これが何をするかは、単に繰り返されたそれぞれのwchar_tcharに割り当てることです - 切り捨て変換。これは std :: string c'tor を使います。

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

コメントで述べたように:

値0〜127は、実質的にすべてのエンコーディングで同じであるため、すべて127未満の値を切り捨てると、同じテキストになります。漢字を入れると失敗するでしょう。

-

windowsコードページ1252(Windows英語のデフォルト)の値128-255とunicodeの値128-255はほとんど同じなので、それを使用しているコードページの場合、これらの文字の大部分を正しい値に切り捨てる必要があります。 (私はáとÂが動くことを期待しています、私たちの仕事中のコードはéのためにこれに依存していることを知っています、私はすぐに直すでしょう)

また、 Win12520x80 - 0x9Fの範囲内のコードポイントは機能しません機能しません。これにはœžŸ、...が含まれます。

117
namar0x0309

あなたがFACTのためにあなたの文字列が変換可能であることを知っているならば、ロケールとすべてのその派手なものを含める代わりに、単にこれをしてください:

#include <iostream>
#include <string>

using namespace std;

int main()
{
  wstring w(L"bla");
  string result;
  for(char x : w)
    result += x;

  cout << result << '\n';
}

実例 こちら

11
Justin Kirk

私は、公式のやり方はまだcodecvtファセットを使うことであると信じています(あなたはある種のロケールを意識した翻訳が必要です)。

resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
  in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);

またはそのようなもの、私は周りに働くコードを持っていません。しかし、私は最近何人の人がその機構を使っているのか、そしてどれだけの人が単にメモリへのポインタを要求してICUまたは他のライブラリに詳細な情報を扱わせるかわからない。

コードには2つの問題があります。

  1. const std::string s( ws.begin(), ws.end() );の変換は、ワイド文字をそれに対応するナロー文字に正しくマップするためには必要ありません。おそらく、それぞれのワイド文字はcharにタイプキャストされるだけです。
    この問題に対する解決策はすでに kemによる回答 で与えられており、ロケールのnarrowファセットのctype関数を含みます。

  2. 同じプログラム内でstd::coutstd::wcoutの両方に出力を書き込んでいます。 coutwcoutは同じストリーム(stdout)に関連付けられており、同じストリームを(coutのように)バイト指向のストリームと(wcoutのように)ワイド指向のストリームとして使用した結果は定義されていません。
    最良のオプションは、狭い(ワイド)出力を同じ(基礎となる)ストリームに混在させないようにすることです。 stdout/cout/wcoutでは、ワイドとナロー出力を切り替えるときにstdoutの向きを切り替えることができます(またはその逆)。

    #include <iostream>
    #include <stdio.h>
    #include <wchar.h>
    
    int main() {
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
        fwide(stdout, -1); // switch to narrow
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
    }
    

Ctypeファセットのnarrowメソッドを直接使うこともできます。

 #include <clocale> 
 #include <locale> 
 #include <文字列> 
#include <vector> 
 
インラインstd :: string narrow(std :: wstring const&text)
 {
 std :: locale const loc( ""); 
 wchar_t const * from = text.c_str( std :: size_t const len = text.size(); 
 std :: vector <char>バッファ(len + 1); 
 std :: use_facet <std :: ctype <wchar_t>>(loc).narrow(from、from + len、 '_'、&buffer [0]); 
 return std :: string(&buffer [0]、&buffer [len]) ; 
} 
6
legalize

この回答を書いている時点で、「convert string wstring」を検索する一番のGoogle検索は、このページに表示されます。私の答えは、文字列をwstringに変換する方法を示していますが、これは実際の質問ではなく、おそらくこの答えを削除する必要がありますが、それは悪い形式と見なされます。このStackOverflow answer 。このページよりも上位になりました。


文字列、wstring、および混合文字列定数をwstringに結合する方法を次に示します。 wstringstreamクラスを使用します。

#include <sstream>

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

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

この解決策は、dk123の解決策に触発されたものですが、ロケールに依存するcodecvtファセットを使用してください。結果はutf8ではなくロケールエンコードされた文字列になります(ロケールとして設定されていない場合)。

std::string w2s(const std::wstring &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}

std::wstring s2w(const std::string &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}

探していましたが見つかりません。最後に、正しいtypenameのstd :: use_facet()関数を使用して、std :: localeから正しいファセットを取得できることを確認しました。お役に立てれば。

3
Vizor

私の場合は、マルチバイト文字(MBCS)を使用する必要があり、std :: stringとstd :: wstringを使用したいと思います。そしてc ++ 11は使えません。だから私はmbstowcsとwcstombsを使います。

New、delete []を使って同じ機能を作りますが、これより遅いです。

これは役に立ちます どのように:さまざまな文字列型の間で変換する

編集

ただし、wstringに変換してソース文字列がアルファベットでもマルチバイト文字列でもない場合は、機能しません。だから私はwcstombsをWideCharToMultiByteに変更します。

#include <string>

std::wstring get_wstr_from_sz(const char* psz)
{
    //I think it's enough to my case
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    size_t len = strlen(psz) + 1;

    if (len >= sizeof(buf) / sizeof(wchar_t))
    {
        pbuf = L"error";
    }
    else
    {
        size_t converted;
        mbstowcs_s(&converted, buf, psz, _TRUNCATE);
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wsz(const wchar_t* pwsz)
{
    char buf[0x400];
    char *pbuf = buf;
    size_t len = wcslen(pwsz)*2 + 1;

    if (len >= sizeof(buf))
    {
        pbuf = "error";
    }
    else
    {
        size_t converted;
        wcstombs_s(&converted, buf, pwsz, _TRUNCATE);
    }

    return std::string(pbuf);
}

EDITで「wcstombs」の代わりに「MultiByteToWideChar」を使用

#include <Windows.h>
#include <boost/shared_ptr.hpp>
#include "string_util.h"

std::wstring get_wstring_from_sz(const char* psz)
{
    int res;
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    boost::shared_ptr<wchar_t[]> shared_pbuf;

    res = MultiByteToWideChar(CP_ACP, 0, psz, -1, buf, sizeof(buf)/sizeof(wchar_t));

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);

        shared_pbuf = boost::shared_ptr<wchar_t[]>(new wchar_t[res]);

        pbuf = shared_pbuf.get();

        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, pbuf, res);
    }
    else if (0 == res)
    {
        pbuf = L"error";
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wcs(const wchar_t* pcs)
{
    int res;
    char buf[0x400];
    char* pbuf = buf;
    boost::shared_ptr<char[]> shared_pbuf;

    res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, buf, sizeof(buf), NULL, NULL);

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, NULL, 0, NULL, NULL);

        shared_pbuf = boost::shared_ptr<char[]>(new char[res]);

        pbuf = shared_pbuf.get();

        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, pbuf, res, NULL, NULL);
    }
    else if (0 == res)
    {
        pbuf = "error";
    }

    return std::string(pbuf);
}
3
heon

デフォルトのエンコーディング

  • Windows UTF-16.
  • Linux UTF-8.
  • MacOS UTF-8.

このコードには、std :: stringをstd :: wstringに、std :: wstringをstd :: stringに変換する2つの形式があります。 WIN32を定義した#ifを無効にしても、同じ結果になります。

1。 std :: stringからstd :: wstringへの変換

MultiByteToWideChar WinAPI

_ mbstowcs_s_l

#if defined WIN32
#include <windows.h>
#endif

std::wstring StringToWideString(std::string str)
{
    if (str.empty())
    {
        return std::wstring();
    }
    size_t len = str.length() + 1;
    std::wstring ret = std::wstring(len, 0);
#if defined WIN32
    int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &str[0], str.size(), &ret[0], len);
    ret.resize(size);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t retval = _mbstowcs_s_l(&size, &ret[0], len, &str[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

2。 std :: wstring to std :: string

WideCharToMultiByte WinAPI

_ wcstombs_s_l

std::string WidestringToString(std::wstring wstr)
{
    if (wstr.empty())
    {
        return std::string();
    }
#if defined WIN32
    int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), NULL, 0, NULL, NULL);
    std::string ret = std::string(size, 0);
    WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), &ret[0], size, NULL, NULL);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t err = _wcstombs_s_l(&size, NULL, 0, &wstr[0], _TRUNCATE, lc);
    std::string ret = std::string(size, 0);
    err = _wcstombs_s_l(&size, &ret[0], size, &wstr[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

3。 Windowsでは、WinAPIを使ってUnicodeを印刷する必要があります。

WriteConsole

#if defined _WIN32
    void WriteLineUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
    }

    void WriteLineUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
    }

4。メインプログラムについて

#if defined _WIN32
int wmain(int argc, WCHAR ** args)
#else
int main(int argc, CHAR ** args)
#endif
{
    std::string source = u8"ÜüΩωЙ你月曜日\na????èéøÞǽлљΣæča????????";
    std::wstring wsource = L"ÜüΩωЙ你月曜日\na????èéøÞǽлљΣæča????????";

    WriteLineUnicode(L"@" + StringToWideString(source) + L"@");
    WriteLineUnicode("@" + WidestringToString(wsource) + "@");
    return EXIT_SUCCESS;
}

5。最後に、コンソールでのUnicode文字に対する強力で完全なサポートが必要です。ConEm を推奨し、 Windowsのデフォルト端末 に設定することをお勧めします。 Visual StudioをConEmuにフックする必要があります。 Visual Studioのexeファイルはdevenv.exeです。

Visual Studio 2017でVC++を使用してテスト済み。 std = c ++ 17.

結果

Result1

2
Joma

他の誰かが興味を持った場合:私はstringwstringのどちらかが期待されるところではどこでも交換可能に使うことができるクラスが必要でした。次のクラスconvertible_stringは、 dk123の解法 に基づいて、stringchar const*wstringまたはwchar_t const*のいずれかで初期化でき、stringまたはwstringのいずれかに代入または暗黙的に変換できますどちらかを取る関数に)。

class convertible_string
{
public:
    // default ctor
    convertible_string()
    {}

    /* conversion ctors */
    convertible_string(std::string const& value) : value_(value)
    {}
    convertible_string(char const* val_array) : value_(val_array)
    {}
    convertible_string(std::wstring const& wvalue) : value_(ws2s(wvalue))
    {}
    convertible_string(wchar_t const* wval_array) : value_(ws2s(std::wstring(wval_array)))
    {}

    /* assignment operators */
    convertible_string& operator=(std::string const& value)
    {
        value_ = value;
        return *this;
    }
    convertible_string& operator=(std::wstring const& wvalue)
    {
        value_ = ws2s(wvalue);
        return *this;
    }

    /* implicit conversion operators */
    operator std::string() const { return value_; }
    operator std::wstring() const { return s2ws(value_); }
private:
    std::string value_;
};
1
James Hirschorn
#include <boost/locale.hpp>
namespace lcv = boost::locale::conv;

inline std::wstring fromUTF8(const std::string& s)
{ return lcv::utf_to_utf<wchar_t>(s); }

inline std::string toUTF8(const std::wstring& ws)
{ return lcv::utf_to_utf<char>(ws); }
0
deep125