Wie konvertiere ich wstring in string?

204

Die Frage ist, wie man wstring in string konvertiert.

Ich habe nächstes 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 auskommentierter Zeile lautet:

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

aber ohne ist nur:

std::wstring =    Hello

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

BEARBEITEN

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.

BЈовић
quelle
4
Wie können Sie diese Frage stellen, ohne auch die Kodierungen anzugeben?
David Heffernan
5
@tenfour: Warum std::wstringüberhaupt verwenden? stackoverflow.com/questions/1049947/…
dalle
11
@dalle Wenn Sie Daten haben, die bereits mit UTF-16 codiert sind, ist es etwas umstritten, ob UTF-16 als schädlich eingestuft wird oder nicht. Und für das, was es wert ist, halte ich keine Transformationsform für schädlich; Was schädlich ist, ist, dass die Leute denken, sie verstehen Unicode, obwohl sie es nicht tun.
David Heffernan
2
Muss es eine plattformübergreifende Lösung sein?
Ali_Bahoo
2
@dalle c ++ Standard erwähnt utf in keiner Weise (utf-8 oder utf-16). Haben Sie einen Link, in dem steht, warum utf-16 nicht mit wstring codiert werden kann?
BЈовић

Antworten:

31

Hier ist eine ausgearbeitete Lösung, die auf den anderen Vorschlägen basiert:

#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.

Philipp
quelle
@Phillip: Welcher Teil des Codes hängt vom c-Gebietsschema ab? wird das std::setlocale(LC_ALL, "");wirklich gebraucht?
Smerlin
2
Die Verwendung std::wcout.imbue(locale)sollte auch die Arbeit erledigen, und es hat den Vorteil, dass es keinen globalen Zustand ändert.
Smerlin
32
Das std::wstring_convertvon C ++ 11 schließt einen Großteil dieses Rauschens ab.
Cubbi
7
@Philipp, was meinst du mit "wird Probleme unter Windows verursachen"? Welche Art von Problemen?
Gili
1
Der obige Code gibt (wie kopiert) gibt mir ein *** glibc detected *** test: malloc(): smallbin double linked list corrupted: 0x000000000180ea30 ***Linux 64-Bit (gcc 4.7.3). Hat das noch jemand erlebt?
Hogliux
312

Wie Cubbi in einem der Kommentare hervorhob, bietet std::wstring_convert(C ++ 11) eine saubere, 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 von verwendet wcstombs langwieriger Zuweisung / Freigabe von Speicher verwendet, bevor ich darauf gestoßen bin.

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

Update (28.11.2013)

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

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

Wrapper-Funktionen können wie folgt 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 als Funktionen oder als Literale an Funktionen übergeben werden soll (aufgrund von C ++ 11 und Compiler-Updates). Ich überlasse die Entscheidung der Person, die sie implementiert, aber es lohnt sich zu wissen.

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

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

dk123
quelle
25
Bitte +1 : Dies ist die offizielle C ++ - Standardmethode für die Konvertierung von Zeichenfolgen. Sie können from_bytes auch verwenden, um in die andere Richtung zu konvertieren. Da ich persönlich Einzeiler mag, ist hier meine Version:std::wstring str = std::wstring_convert<std::codecvt_utf<wchar_t>>().from_bytes("some string");
Guss
7
Es sieht so aus, als ob en.cppreference.com/w/cpp/header/codecvt ab g ++ 4.8.2 nicht verfügbar ist. Die beiden Methoden s2ws und ws2s funktionieren derzeit nicht unter Linux
Begui
5
Es sieht so aus, als wäre dies veraltet ( stackoverflow.com/a/42946556/211176 ). Mein Compiler wirft Fehler aus, wenn ich versuche, diesen Code auszuführen
adam_0
5
Für alle, die sich über C ++ 17 und weitere Kompatibilität (aufgrund von Veralterung
Timo
128

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 keine Zeichensatzkonvertierung stattfindet. Was dies bedeutet ist einfach zuweisen jede iterativ wchar_tzu einem char- eine Kürzen Umwandlung. Es verwendet den 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, sodass das Abschneiden von Werten, die alle kleiner als 127 sind, zu demselben Text führt. Geben Sie einen chinesischen Charakter ein und Sie werden den Fehler sehen.

- -

Die Werte 128-255 der Windows-Codepage 1252 (die Windows-Standardeinstellung für Englisch) und die Werte 128-255 des Unicodes sind größtenteils gleich. Wenn dies also die Codepage ist, die Sie verwenden, sollten die meisten dieser Zeichen auf die richtigen Werte gekürzt werden. (Ich habe total erwartet, dass á und õ funktionieren, ich weiß, dass unser Code bei der Arbeit davon abhängt, was ich bald beheben werde)

Und beachten Sie, dass Codepunkte im Bereich 0x80 - 0x9Fin Win1252 wird nicht funktionieren. Dazu gehört , œ, ž, Ÿ, ...

namar0x0309
quelle
2
Seltsamerweise funktioniert dies in Visual Studio 10. Was ist los? Dies sollte dazu führen, dass die Zuweisung von wchar_t zu char für alle Elemente der ursprünglichen Zeichenfolge abgeschnitten wird.
Pedro Lamarão
6
... wenn es um nicht-lateinische Zeichen geht.
JavaRunner
8
@ PedroLamarão: Die Werte 0-127 sind in praktisch jeder Codierung identisch, sodass das Abschneiden von Werten, die alle kleiner als 127 sind, zum gleichen Text führt. Geben Sie einen chinesischen Charakter ein und Sie werden den Fehler sehen.
Mooing Duck
3
@ PedroLamarão: Die Werte 128-255 der Windows-Codepage 1252 (die Windows-Standardeinstellung für Englisch) und die Werte 128-255 des Unicodes sind größtenteils identisch. Wenn dies also die Codepage ist, die Sie verwenden, sollten die meisten dieser Zeichen auf das richtige Maß gekürzt werden Werte. (Ich hatte total erwartet, dass á und õ funktionieren, ich weiß, dass unser Code bei der Arbeit darauf beruht, was ich bald beheben werde)
Mooing Duck
2
Das funktioniert super. MSVS 2015 und MSVS 2017 und MINGW / g ++ und clang ++. Legit ++ 1.
Nikos
11

Wenn Sie wissen, dass Ihre Zeichenfolge konvertierbar ist, tun Sie einfach Folgendes, anstatt das Gebietsschema und all diese ausgefallenen Dinge einzuschließen:

#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

rubenvb
quelle
2
+1, weil es eine einfache Lösung ist, die für einige Szenarien funktioniert (für eine lose Definition von "funktioniert" könnte ich hinzufügen).
Rabe
2
Fast das Gleiche wie die Lösung von namar0x0309, die meiner Meinung nach viel eleganter ist. Aber das bin nur ich.
Onitake
Ich habe Ihren Code aufgepeppt, um tatsächlich mit minimalen Änderungen zu arbeiten ;-)
rubenvb
9
-1 Wenn Sie eine Zeichenfolge haben, handelt es sich wahrscheinlich um Multibyte-Zeichen. Wenn Sie wissen könnten, dass die Zeichenfolge trivial konvertierbar ist, würden Sie überhaupt nicht mit einer Zeichenfolge umgehen. Wahrscheinlicher ist, dass Sie es mit einer anderen Bibliothek zu tun haben, die erwartet, dass Sie mit dem Wstring richtig umgehen. Das Abschneiden der Wchars bittet später nur um einen schwer zu verfolgenden Fehler. Außerdem sollten Sie "string result (w.begin (), w.end ())" verwenden. Wenn Sie dies tun würden, vermeiden Sie eine Schleife, die viele Neuzuweisungen auslösen könnte.
Kian
7

Ich glaube, der offizielle Weg besteht immer noch darin, durch codecvtFacetten zu gehen (Sie benötigen eine länderspezifische Übersetzung), 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 mir nicht sicher, wie viele Leute heutzutage diese Maschinerie benutzen und wie viele einfach nach Zeigern auf das Gedächtnis fragen und die Intensivstation oder eine andere Bibliothek die blutigen Details behandeln lassen.

Christopher Creutzig
quelle
7

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 korrekt ihrem schmalen Gegenstück zuzuordnen. Höchstwahrscheinlich wird jedes breite Zeichen nur typisiert char.
    Die Lösung für dieses Problem ist bereits in der Antwort von kem angegeben und beinhaltet die narrowFunktion der ctypeFacette des Gebietsschemas .

  2. Sie schreiben die Ausgabe in beide std::coutund std::wcoutim selben Programm. Beide coutund wcoutsind demselben Stream ( stdout) zugeordnet, und die Ergebnisse der Verwendung desselben Streams sowohl als byteorientierter Stream (wie es der coutFall ist) als auch als breiter orientierter Stream (wie es der wcoutFall ist) sind nicht definiert.
    Die beste Option besteht darin, zu vermeiden, dass schmale und breite Ausgaben mit demselben (zugrunde liegenden) Stream gemischt werden. Für stdout/ cout/ wcoutkönnen Sie versuchen, die Ausrichtung zu stdoutändern, wenn Sie zwischen breitem und schmalem Ausgang 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;
    }
Bart van Ingen Schenau
quelle
Ja, das behebt das Problem bei der Verwendung von cout und wcout.
BЈовић
7

Standardcodierung ein:

  • 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 negiertes 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. Im 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 ConEmu und setze es als Standardterminal unter Windows . Sie müssen Visual Studio mit ConEmu verbinden. Denken Sie daran, dass die exe-Datei von Visual Studio lautet devenv.exe lautet

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

Ergebnis

Ergebnis1

Joma
quelle
6

Sie können auch die enge Methode der ctype-Facette direkt 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]);
}}
legalisieren
quelle
6

Zum Zeitpunkt des Schreibens dieser Antwort würde Sie die erste Google-Suche nach "string 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. Möglicherweise möchten Sie zu dieser StackOverflow-Antwort springen , die jetzt einen höheren Rang als diese Seite hat.


Hier ist eine Möglichkeit, String-, Wstring- und gemischte String-Konstanten mit 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();
Mark Lakata
quelle
13
Dies ist keine String-zu-String-Konvertierung
Poitroae
1
@ Michael Kannst du bitte erklären? Was ist daran falsch? Ihr Kommentar ist ohne weitere Details nicht hilfreich.
Nate
1
Dies ist eine Konvertierung von String zu Wstring. dh das Gegenteil der Frage.
Jeff McClintock
4

Neben der Konvertierung der Typen sollten Sie sich auch des tatsächlichen Formats der Zeichenfolge bewusst sein.

Beim Kompilieren für einen Multi-Byte-Zeichensatz setzt Visual Studio und die Win-API UTF8 voraus (tatsächlich Windows- Codierung, Windows-28591 ).
Beim Kompilieren für den Unicode-Zeichensatz setzt Visual Studio und die Win-API UTF16 voraus.

Sie müssen also auch die Zeichenfolge vom UTF16- in das UTF8-Format konvertieren und nicht nur in std :: string konvertieren.
Dies ist erforderlich, wenn Sie mit Formaten mit mehreren Zeichen wie einigen nicht-lateinischen Sprachen arbeiten.

Die Idee ist zu entscheiden, dass std::wstring immer UTF16 repräsentiert .
Und repräsentiert std::string immer UTF8 .

Dies wird vom Compiler nicht erzwungen, sondern ist eher eine gute Richtlinie. Beachten Sie die Zeichenfolgenpräfixe, mit denen ich UTF16 ( L ) und UTF8 ( u8 ) definiere.

Um zwischen den beiden Typen zu konvertieren, sollten Sie Folgendes verwenden: std :: codecvt_utf8_utf16 <wchar_t>

#include <string>

#include <codecvt>

int main()
{

    std::string original8 = u8"הלו";

    std::wstring original16 = L"הלו";

    //C++11 format converter
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    //convert to UTF8 and std::string
    std::string utf8NativeString = convert.to_bytes(original16);

    std::wstring utf16NativeString = convert.from_bytes(original8);

    assert(utf8NativeString == original8);
    assert(utf16NativeString == original16);

    return 0;
}
Yochai Timmer
quelle
3

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

BEARBEITEN

Wenn die Konvertierung in eine Zeichenfolge und eine Quellzeichenfolge jedoch kein Alphabet und keine Mehrbytezeichenfolge ist, funktioniert dies nicht. Also ändere ich wcstombs in 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 zu verwenden ‚MultiByteToWideChar‘ anstelle von ‚wcstombs‘

#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);
}
er auf
quelle
Wie kann ich "wcstombs_s" mit gcc 4.8 verwenden? Weil ich sehe, dass dies eine C ++ 11-Funktion ist.
Cristian
@cristian Sie können die "unsichere" Version dieser Funktion verwenden wcstombs().
Vizor
3

Diese Lösung ist von der Lösung von dk123 inspiriert , verwendet jedoch eine vom Gebietsschema abhängige Codecvt-Facette. Das Ergebnis ist eine in einem Gebietsschema codierte Zeichenfolge anstelle von UTF-8 (wenn es nicht als Gebietsschema 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 die richtige Facette erhalten kann, wenn ich std::localedie std::use_facet()Funktion mit dem richtigen Typnamen verwende. Hoffe das hilft.

Visier
quelle
Vizor, was sind die Vorteile (falls vorhanden) der Konvertierung mit der vom Gebietsschema abhängigen Facette?
März 2377
Wenn Sie mit Zeichenfolgen aus dem System arbeiten, z. B. über die Konsoleneingabe.
Vizor
1

Falls jemand anderes interessiert ist: Ich brauchte eine Klasse, die austauschbar verwendet werden kann, wo immer eine stringoder wstringerwartet wird. Die folgende Klasse convertible_string, basierend auf dk123-Lösung kann entweder mit einem initialisiert werden string, char const*, wstringoder wchar_t const*und kann durch oder implizit entweder einen umgebautes zugeordnet werden stringoder wstring(so in eine Funktion übergeben werden , die entweder übernehmen).

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_;
};
James Hirschorn
quelle
1
Ich würde lieber eine aufbewahren std::wstring in der Klasse speichern, als std::stringeine Konvertierung zu speichern und durchzuführen, std::wstringwenn dies erforderlich ist, um eine zu erhalten std::wstring. Weil std::wstringist etwas schneller als std::stringund es ist besser kompatibel. Auch es verbraucht mehr Speicher als std::string.
0xAA55
0
#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); }
deep125
quelle
-1

Ich verwende unten, um wstring in string umzuwandeln.

std::string strTo;
char *szTo = new char[someParam.length() + 1];
szTo[someParam.size()] = '\0';
WideCharToMultiByte(CP_ACP, 0, someParam.c_str(), -1, szTo, (int)someParam.length(), NULL, NULL);
strTo = szTo;
delete szTo;
Arun
quelle
Sie scheinen einen Standardheader ( <string>) und eine Definition für WideCharToMultiByte()- fehlt das ein Wrapper std::wctomb()?
Toby Speight
-3
// Embarcadero C++ Builder 

// convertion string to wstring
string str1 = "hello";
String str2 = str1;         // typedef UnicodeString String;   -> str2 contains now u"hello";

// convertion wstring to string
String str2 = u"hello";
string str1 = UTF8string(str2).c_str();   // -> str1 contains now "hello"
Necips
quelle
3
Bitte erklären Sie, was Sie dort in Ihrer Antwort tun, sonst wird es möglicherweise gelöscht
CodeFanatic
1
Woher kommt die UTF8string-Funktion?
Jean-Christophe Blanchard