wake-up-neo.com

Wie konvertiere ich wstring in string?

Die Frage ist, wie man wstring in string konvertiert.

Ich habe folgendes Beispiel:

#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;
}

die Ausgabe mit der auskommentierten Zeile ist:

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

aber ohne ist nur:

std::wstring =    Hello

Stimmt etwas mit dem Beispiel nicht? Kann ich die Konvertierung wie oben durchführen?

EDIT

Neues Beispiel (unter Berücksichtigung einiger Antworten) ist

#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;
}

Die Ausgabe ist:

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

daher kann der Stringstream nicht zum Konvertieren von wstring in string verwendet werden.

185
BЈовић

Hier ist eine ausgearbeitete Lösung basierend auf den anderen Vorschlägen:

#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;
  }
}

Dies funktioniert normalerweise unter Linux, führt jedoch unter Windows zu Problemen.

29
Philipp

Wie Cubbi in einem der Kommentare hervorhob, std::wstring_convert (C++ 11) bietet eine ordentlich einfache Lösung (Sie müssen #include<locale> und <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 );

Ich habe eine Kombination aus wcstombs und mühsamer Zuweisung/Freigabe von Speicher verwendet, bevor ich darauf gestoßen bin.

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

Update (2013.11.28)

Ein Liner kann so angegeben werden (Danke Guss für deinen Kommentar):

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

Wrapper-Funktionen können folgendermaßen angegeben werden: (Vielen Dank, ArmanSchwarz, für Ihren Kommentar)

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);
}

Hinweis: Es gibt einige Kontroversen darüber, ob string/wstring an Funktionen als Referenzen oder als Literale übergeben werden soll (aufgrund von C++ 11- und Compiler-Updates). Ich überlasse die Entscheidung der ausführenden Person, aber es lohnt sich zu wissen.

Hinweis: Ich verwende std::codecvt_utf8 im obigen Code, aber wenn Sie nicht UTF-8 verwenden, müssen Sie dies in die entsprechende Codierung ändern, die Sie verwenden:

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

286
dk123

Lösung von: 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;

Beachten Sie , dass hier überhaupt eine nein Zeichensatzkonvertierung stattfindet. Damit wird einfach jedem iterierten wchar_t in ein char - eine abschneidende Konvertierung. Es verwendet das std :: string c'tor :

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

Wie in den Kommentaren angegeben:

die Werte 0-127 sind in praktisch jeder Codierung identisch. Wenn Sie also Werte kürzen, die kleiner als 127 sind, erhalten Sie denselben Text. Geben Sie ein chinesisches Schriftzeichen ein und Sie werden den Fehler sehen.

-

die Werte 128-255 der Windows-Codepage 1252 (die Standardeinstellung von Windows Englisch) und 128-255 von Unicode sind größtenteils gleich. Wenn Sie also die Codepage verwenden, sollten die meisten dieser Zeichen auf die richtigen Werte gekürzt werden. (Ich habe absolut damit gerechnet, dass á und õ funktionieren, ich weiß, dass unser Code bei der Arbeit für é darauf beruht, was ich bald beheben werde.)

Und beachte, dass der Code im Bereich 0x80 - 0x9F in Win1252 wird nicht funktionieren. Das beinhaltet , œ, ž, Ÿ, ...

120
namar0x0309

Wenn Sie wissen, dass Ihre Zeichenfolge für FACT konvertierbar ist, anstatt das Gebietsschema und all die ausgefallenen Elemente einzuschließen, gehen Sie wie folgt vor:

#include <iostream>
#include <string>

using namespace std;

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

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

Live-Beispiel hier

11
Justin Kirk

Ich glaube, der offizielle Weg ist immer noch, durch codecvt Facetten zu gehen (Sie brauchen eine Art von Übersetzung, die sich der Ländereinstellung bewusst ist), wie in

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

oder so ähnlich, ich habe keinen Arbeitscode herumliegen. Aber ich bin nicht sicher, wie viele Leute heutzutage diese Maschinerie benutzen und wie viele einfach nach Hinweisen auf das Gedächtnis fragen und ICU oder eine andere Bibliothek mit den blutigen Details umgehen lassen.

Es gibt zwei Probleme mit dem Code:

  1. Die Konvertierung in const std::string s( ws.begin(), ws.end() ); ist nicht erforderlich, um die breiten Zeichen ihrem schmalen Gegenstück korrekt zuzuordnen. Höchstwahrscheinlich wird jedes breite Zeichen nur in char umgewandelt.
    Die Lösung für dieses Problem ist bereits in die Antwort von kem angegeben und bezieht die narrow -Funktion der ctype -Facette des Gebietsschemas ein.

  2. Sie schreiben eine Ausgabe an beide std::cout und std::wcout im selben Programm. Sowohl cout als auch wcout sind demselben Stream (stdout) zugeordnet, und die Ergebnisse der Verwendung desselben Streams als byteorientierter Stream (als cout does) und ein breit orientierter Stream (wie wcout does) sind nicht definiert.
    Die beste Möglichkeit besteht darin, zu vermeiden, dass enge und breite Ausgaben mit demselben (zugrunde liegenden) Stream gemischt werden. Bei stdout/cout/wcout können Sie versuchen, die Ausrichtung von stdout zu ändern, wenn Sie zwischen einer breiten und einer schmalen Ausgabe wechseln (oder umgekehrt):

    #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;
    }
    

Sie können auch direkt die enge Methode der ctype-Facette verwenden:

 # include <clocale> 
 # include <locale> 
 # include <string> 
 # include <vector> 
 
 inline std :: string eng (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> -Puffer (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

Zum Zeitpunkt des Schreibens dieser Antwort würde Sie die Nummer eins der Google-Suche nach "convert string wstring" auf dieser Seite landen. Meine Antwort zeigt, wie man einen String in einen wstring konvertiert, obwohl dies NICHT die eigentliche Frage ist, und ich sollte diese Antwort wahrscheinlich löschen, aber das wird als schlechte Form angesehen. Vielleicht möchten Sie zu diese StackOverflow-Antwort , die jetzt einen höheren Rang als diese Seite hat.


Hier ist eine Möglichkeit, String-, Wstring- und gemischte String-Konstanten zu Wstring zu kombinieren. Verwenden Sie die Klasse 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

Standardcodierung am:

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

Dieser Code hat zwei Formen, um std :: string in std :: wstring und std :: wstring in std :: string zu konvertieren. Wenn Sie #if defined WIN32 negieren, erhalten Sie das gleiche Ergebnis.

1. std :: string zu 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 zu 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. Unter Windows müssen Sie Unicode mit WinAPI drucken.

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. Auf Hauptprogramm.

#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. Schließlich benötigen Sie eine leistungsstarke und vollständige Unterstützung für Unicode-Zeichen in der Konsole. Ich empfehle ConEm und setze Standardterminal unter Windows . Sie müssen Visual Studio mit ConEmu verbinden. Denken Sie daran, dass die Exe-Datei von Visual Studio devenv.exe ist.

Getestet in Visual Studio 2017 mit VC++; std = c ++ 17.

Ergebnis

Result1

3
Joma

Diese Lösung ist von der dk123-Lösung inspiriert, verwendet jedoch eine vom Gebietsschema abhängige Codecvt-Facette. Das Ergebnis ist eine in der Ländereinstellung codierte Zeichenfolge anstelle von utf8 (wenn es nicht als Ländereinstellung festgelegt ist):

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);
}

Ich habe danach gesucht, aber ich kann es nicht finden. Schließlich stellte ich fest, dass ich mit der Funktion std :: use_facet () mit dem richtigen Typnamen die richtige Facette aus std :: locale erhalten kann. Hoffe das hilft.

3
Vizor

In meinem Fall muss ich ein Multibyte-Zeichen (MBCS) verwenden und ich möchte std :: string und std :: wstring verwenden. Und kann C++ 11 nicht verwenden. Also benutze ich mbstowcs und wcstombs.

Ich mache die gleiche Funktion mit new, delete [], aber es ist langsamer als dies.

Dies kann helfen Gewusst wie: Konvertieren zwischen verschiedenen Zeichenfolgentypen

[~ # ~] edit [~ # ~]

Bei der Konvertierung in wstring und source string werden jedoch keine Buchstaben- und Mehrbytezeichenfolgen verwendet. Dies funktioniert jedoch nicht. Also ändere ich wcstombs zu 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);
}

[~ # ~] Bearbeiten Sie [~ # ~] , um 'MultiByteToWideChar' anstelle von 'wcstombs' zu verwenden.

#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

Falls jemand anderes interessiert ist: Ich brauchte eine Klasse, die überall dort austauschbar ist, wo ein string oder wstring erwartet wurde. Die folgende Klasse convertible_string, basierend auf dk123s Lösung , kann entweder mit string, char const*, wstring oder wchar_t const* und kann entweder einem string oder wstring zugewiesen oder implizit konvertiert werden (kann also an eine Funktion übergeben werden, die eines von beiden übernimmt).

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