C ++ Konvertiere String (oder char *) in wstring (oder wchar_t *)

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

Wie würde ich den Inhalt von s ws zuweisen?

Google gesucht und einige Techniken verwendet, aber sie können nicht den genauen Inhalt zuweisen. Der Inhalt ist verzerrt.

Samir
quelle
7
Ich glaube nicht, dass strings> 8-Bit-Zeichen akzeptiert werden. Ist es bereits in UTF-8 codiert?
Kennytm
3
Was ist Ihre Systemcodierung, die "おはよう"eine systemcodierte Zeichenfolge ergeben würde?
sbi
Ich glaube, MSVC wird das akzeptieren und eine Multibyte-Codierung vornehmen, vielleicht UTF-8.
Potatoswatter
1
@Potatoswatter: MSVC verwendet UTF-8 standardmäßig nicht für ALLES. Wenn Sie diese Zeichen eingeben, werden Sie gefragt, in welche Codierung die Datei konvertiert werden soll, und standardmäßig die Codepage 1252.
Mooing Duck
2
@ Samir: Wichtiger ist die Kodierung der Datei ? Können Sie diese Zeichenfolge an den Anfang der Datei verschieben und einen Hexdump dieses Teils anzeigen? Daran können wir es wahrscheinlich erkennen.
Mooing Duck

Antworten:

239

Angenommen, die Eingabezeichenfolge in Ihrem Beispiel (お は よ う) ist eine UTF-8-codierte Darstellung (was anscheinend nicht der Fall ist, aber nehmen wir an, dass dies der Erklärung dient :-)) einer Unicode-Zeichenfolge Wenn Sie dies interessieren, kann Ihr Problem allein mit der Standardbibliothek (C ++ 11 und neuer) vollständig gelöst werden.

Die TL; DR-Version:

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

Längeres online kompilierbares und ausführbares Beispiel:

(Sie alle zeigen das gleiche Beispiel. Es gibt nur viele für Redundanz ...)

Anmerkung (alt) :

Wie in den Kommentaren erwähnt und unter https://stackoverflow.com/a/17106065/6345 erläutert, kann es vorkommen, dass die Verwendung der Standardbibliothek zum Konvertieren zwischen UTF-8 und UTF-16 zu unerwarteten Unterschieden bei den Ergebnissen auf verschiedenen Plattformen führt . Beachten Sie für eine bessere Konvertierung std::codecvt_utf8die Beschreibung unter http://en.cppreference.com/w/cpp/locale/codecvt_utf8

Hinweis (neu) :

Da der codecvtHeader in C ++ 17 veraltet ist, wurden einige Bedenken hinsichtlich der in dieser Antwort vorgestellten Lösung geäußert. Allerdings fügte das C ++ Normenausschuss eine wichtige Aussage in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html sagen

Diese Bibliothekskomponente sollte nebenbei in Anhang D eingestellt werden, bis ein geeigneter Ersatz standardisiert ist.

In absehbarer Zeit ist die codecvtLösung in dieser Antwort sicher und tragbar.

Johann Gerell
quelle
2
Überprüfen Sie, mit welcher Codierung Sie VS-Dateien speichern
Johann Gerell
9
Beachten Sie, dass dies nur C ++ 11 ist!
bk138
1
In minGW (gcc / g ++ 4.8.1 und -std = c ++ 11) existiert der Codecvt-Header nicht. Gibt es eine Alternative?
Brian Jack
1
Bitte geben Sie ein Beispiel std::codecvt_utf8für Anfänger
Noitidart
14
Bitte beachten Sie, dass dies <codecvt>seit C ++ 17 veraltet ist.
Tambre
47
int StringToWString(std::wstring &ws, const std::string &s)
{
    std::wstring wsTmp(s.begin(), s.end());

    ws = wsTmp;

    return 0;
}
Pietro M.
quelle
93
Dies funktioniert nur, wenn alle Zeichen Einzelbyte sind, dh ASCII oder ISO-8859-1 . Alles, was mit mehreren Bytes zu tun hat, schlägt kläglich fehl, einschließlich UTF-8. Die Frage enthält eindeutig Mehrbytezeichen.
Mark Ransom
28
Diese Antwort ist eindeutig unzureichend und kopiert nur schmale Zeichen in breite Zeichen. In den anderen Antworten, insbesondere der von Johann Gerell, erfahren Sie, wie Sie von einer Multi-Byte- oder utf8-codierten Zeichenfolge zu einer utf16-Zeichenfolge wechseln.
DLRdave
10
Diese Antwort ist gefährlich und wird wahrscheinlich auf einem Nicht-ASCII-System brechen. dh ein arabischer Dateiname wird durch diesen Hack entstellt.
Stephen
9
Diese Antwort ist nützlich, wenn Sie die Nuance des Fragentextes ignorieren und sich auf den Fragentitel konzentrieren, der mich von Google hierher gebracht hat. Wie es ist, ist der Titel der Frage äußerst irreführend und sollte geändert werden, um die wahre Frage widerzuspiegeln
Anne Quinn
3
Dies funktioniert nur für 7-Bit-ASCII-Zeichen. Für latin1 funktioniert es nur, wenn char als vorzeichenlos konfiguriert ist. Wenn der Typ char signiert ist (was meistens der Fall ist), führen Zeichen> 127 zu falschen Ergebnissen.
Huyc
32

Ihre Frage ist nicht genau spezifiziert. Genau genommen ist dieses Beispiel ein Syntaxfehler. Es std::mbstowcsist jedoch wahrscheinlich das, wonach Sie suchen.

Es ist eine C-Bibliotheksfunktion und arbeitet mit Puffern, aber hier ist eine benutzerfreundliche Redewendung, mit freundlicher Genehmigung von TBohne (ehemals 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.
Kartoffelklatsche
quelle
1
Zeichenfolge 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 = verzerrt
Samir
1
@Samir: Sie müssen sicherstellen, dass die Laufzeitcodierung mit der Codierung zur Kompilierungszeit übereinstimmt. Möglicherweise müssen Sie setlocaleCompiler-Flags anpassen oder anpassen. Ich weiß es nicht, weil ich kein Windows verwende, aber deshalb ist es keine übliche Funktion. Betrachten Sie die andere Antwort, wenn möglich.
Potatoswatter
1
std::string ws(s.size()); ws.resize(mbstowcs(&ws[0], s.c_str(), s.size());RAII FTW
Mooing Duck
2
@WaffleSouffle Das ist veraltet. Seit 2011 sind zusammenhängende Implementierungen erforderlich, und Implementierungen haben solche Tricks lange vorher beendet.
Potatoswatter
1
und einige Umgebungen wie mingw haben immer noch keinen Codecvt-Header, so dass einige der "besseren" Lösungen früher nicht funktionieren, was bedeutet, dass dieses Problem auch ab Dezember 2014 noch keine guten Lösungen in mingw hat
Brian Jack
18

Nur Windows-API, vor der Implementierung von C ++ 11, falls jemand sie benötigt:

#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);
}
Alex Che
quelle
Sie können es optimieren. Es ist nicht erforderlich, die Zeichenfolge mit a doppelt zu kopieren vector. Reservieren Sie einfach die Zeichen in der Zeichenfolge wstring strW(charsNeeded + 1);und verwenden Sie sie dann als Puffer für die Konvertierung : &strW[0]. strW[charsNeeded] = 0;
Stellen Sie
1
@ c00000fd Soweit ich weiß, muss der interne Puffer std :: basic_string erst seit dem C ++ 11-Standard kontinuierlich sein. Mein Code ist vor C ++ 11, wie oben im Beitrag angegeben. Daher wäre der & strW [0] -Code nicht standardkonform und könnte zur Laufzeit legitim abstürzen.
Alex Che
13

Wenn Sie Windows / Visual Studio verwenden und eine Zeichenfolge in wstring konvertieren müssen, können Sie Folgendes verwenden:

#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());

Gleiches Verfahren zum Konvertieren einer Zeichenfolge in eine Zeichenfolge (manchmal müssen Sie eine Codepage angeben ):

#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());

Sie können eine Codepage und sogar UTF8 angeben (das ist ziemlich gut, wenn Sie mit JNI / Java arbeiten ). In dieser Antwort wird eine Standardmethode zum Konvertieren eines std :: wstring in utf8 std :: string gezeigt .

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

Wenn Sie mehr über Codepages erfahren möchten, gibt es einen interessanten Artikel über Joel über Software: Das absolute Minimum, das jeder Softwareentwickler unbedingt über Unicode und Zeichensätze wissen muss .

Diese CA2W-Makros (Convert Ansi to Wide = Unicode) sind Teil der ATL- und MFC-String-Konvertierungsmakros , einschließlich Beispielen.

Manchmal müssen Sie die Sicherheitswarnung # 4995 'deaktivieren. Ich kenne keine andere Problemumgehung (für mich passiert dies, wenn ich in VS2012 für Windows XP kompiliert habe).

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

Bearbeiten: Nun, laut diesem Artikel scheint der Artikel von Joel zu sein: "Während unterhaltsam, ist es ziemlich leicht auf tatsächlichen technischen Details". Artikel: Was jeder Programmierer unbedingt positiv über Codierung und Zeichensätze wissen muss, um mit Text arbeiten zu können .

lmiguelmh
quelle
Entschuldigung, ich bin kein englischer Muttersprachler. Bitte bearbeiten Sie nach Belieben.
lmiguelmh
Was ist mit dem Downvoter los? Was ist falsch an der Antwort?
lmiguelmh
Wahrscheinlich die Tatsache, dass es nicht portablen Code fördert.
Pavel Minaev
Ja, deshalb habe ich angegeben, dass dies nur in Windows / Visual Studio funktioniert. Aber zumindest ist diese Lösung richtig und nicht diese:char* str = "hello worlddd"; wstring wstr (str, str+strlen(str));
lmiguelmh
Zusätzlicher Hinweis: CA2W befindet sich unter dem Namespace von ATL. (ATL :: CA2W)
Val
12

Hier ist eine Möglichkeit string, wstringString-Konstanten zu kombinieren und zu mischen wstring. Verwenden Sie die wstringstreamKlasse.

Dies funktioniert NICHT für Mehrbyte-Zeichencodierungen. Dies ist nur eine blöde Methode, um die Typensicherheit wegzuwerfen und 7-Bit-Zeichen von std :: string in die unteren 7 Bits jedes Zeichens von std: wstring zu erweitern. Dies ist nur nützlich, wenn Sie über 7-Bit-ASCII-Zeichenfolgen verfügen und eine API aufrufen müssen, für die breite Zeichenfolgen erforderlich sind.

#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();
Mark Lakata
quelle
Die Antwort scheint interessant. Könnten Sie bitte etwas erklären: Funktioniert dies für Multi-Byte-Codierungen und warum / wie?
wh1t3cat1k
Codierungsschemata sind orthogonal zur Speicherklasse. stringspeichert 1-Byte-Zeichen und wstringspeichert 2-Byte-Zeichen. so etwas wie utf8 speichert Mulitbyte-Zeichen als eine Reihe von 1-Byte-Werten, dh in a string. Die Zeichenfolgenklassen helfen nicht bei der Codierung. Ich bin kein Experte für das Codieren von Klassen in C ++.
Mark Lakata
2
Gibt es einen Grund, warum dies nicht die beste Antwort ist, wenn man bedenkt, wie kurz und einfach es ist? Gibt es Fälle, die nicht abgedeckt sind?
Ryuu
@ MarkLakata, ich habe deine Antwort auf den ersten Kommentar gelesen, bin mir aber immer noch nicht sicher. Funktioniert es für Multi-Byte-Zeichen? Mit anderen Worten, ist es nicht anfällig für die gleiche Gefahr wie diese Antwort ?
März 2377
@ Marc.2377 Dies funktioniert NICHT für Mehrbyte-Zeichencodierungen. Dies ist nur eine blöde Art, die Typensicherheit wegzuwerfen und 7-Bit-Zeichen von std::stringin die unteren 7-Bits jedes Zeichens von zu erweitern std:wstring. Dies ist nur nützlich, wenn Sie über 7-Bit-ASCII-Zeichenfolgen verfügen und eine API aufrufen müssen, für die breite Zeichenfolgen erforderlich sind. Schauen Sie sich stackoverflow.com/a/8969776/3258851 an, wenn Sie etwas Anspruchsvolleres benötigen.
Mark Lakata
11

Von char*bis wstring:

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

Von stringbis wstring:

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

Beachten Sie, dass dies nur gut funktioniert, wenn die zu konvertierende Zeichenfolge nur ASCII-Zeichen enthält.

Ghominejad
quelle
7
Weil dies nur funktioniert, wenn die Codierung Windows-1252 ist, das nicht einmal die Buchstaben in der Frage enthalten kann.
Mooing Duck
3
Dies ist die am wenigsten fehleranfällige Methode, wenn Sie wissen, dass Sie mit ASCII zu tun haben. Dies ist ein wichtiger Anwendungsfall beim Portieren von Apps auf neuere APIs.
Sid Sarasvati
Dies ist nicht der Weg. Wenn Sie Visual Studio verwenden, sollten Sie verwenden atlconv.h. Überprüfen Sie die anderen Antworten.
lmiguelmh
7

mit Boost.Locale:

ws = boost::locale::conv::utf_to_utf<wchar_t>(s);
vladon
quelle
5

Diese Variante ist mein Favorit im wirklichen Leben. Es konvertiert die Eingabe, wenn sie UTF-8 gültig ist , in die entsprechende wstring. Wenn die Eingabe beschädigt ist, wstringwird die aus den einzelnen Bytes aufgebaut. Dies ist äußerst hilfreich, wenn Sie sich über die Qualität Ihrer Eingabedaten nicht sicher sein können.

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;
    }
}
Matthias Ronge
quelle
1
Ich habe gerade diese Frage basierend auf Ihrer Antwort gestapelt. Stoveroverflow.com/questions/49669048/… können Sie einen Blick darauf werfen
MistyD
2

Wenn Sie QT haben und faul sind, eine Funktion und Dinge zu implementieren, die Sie verwenden können

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

Kadir Erdem Demir
quelle
Fast, aber Sie sollten einfach mit a beginnen QString, da der QStringKonstruktor aus irgendeinem Grund keine Zeichenfolge akzeptieren kann.
Bobbeenjamin
1
Sie können doc.qt.io/qt-5/qstring.html#fromStdString
Kadir Erdem Demir
Das ist nett. Sie können auch .c_str () verwenden , damit QString Ihre Zeichenfolge im Konstruktor akzeptiert.
Miep
1

Methode s2ws funktioniert gut. Hoffnung hilft.

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;
}
hahakubile
quelle
6
Was ist mit all diesen Antworten, die den dynamischen Speicher auf unsichere Weise zuweisen und dann die Daten aus dem Puffer in die Zeichenfolge kopieren? Warum wird niemand den unsicheren Mittelsmann los?
Mooing Duck
hahakubile, kannst du bitte mit etwas ähnlichem für ws2s helfen?
Cristian
1

Basierend auf meinen eigenen Tests (unter Windows 8, vs2010) können mbstowcs tatsächlich die ursprüngliche Zeichenfolge beschädigen. Sie funktionieren nur mit der ANSI-Codepage. Wenn MultiByteToWideChar / WideCharToMultiByte auch eine Beschädigung von Zeichenfolgen verursachen kann, ersetzen sie jedoch Zeichen, die sie nicht kennen, durch '?' Fragezeichen, aber mbstowcs neigt dazu anzuhalten, wenn es auf ein unbekanntes Zeichen stößt und an dieser Stelle eine Zeichenfolge abschneidet. (Ich habe vietnamesische Schriftzeichen an finnischen Fenstern getestet).

Ziehen Sie daher die Multi * -Fenster-API-Funktion den analogen Ansi C-Funktionen vor.

Ich habe auch festgestellt, dass der kürzeste Weg zum Codieren von Zeichenfolgen von einer Codepage zur anderen darin besteht, nicht die API-Funktionsaufrufe MultiByteToWideChar / WideCharToMultiByte zu verwenden, sondern deren analoge ATL-Makros: W2A / A2W.

Die oben erwähnte analoge Funktion klingt also wie folgt:

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

_acp wird im Makro USES_CONVERSION deklariert.

Oder auch eine Funktion, die ich oft vermisse, wenn ich alte Daten in neue konvertiere:

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

   _acp = CP_UTF8;
   return W2A( pw );
}

Beachten Sie jedoch, dass diese Makros stark gestapelt sind - nicht für Schleifen oder rekursive Schleifen für dieselbe Funktion - nach Verwendung des W2A- oder A2W-Makros - besser so schnell wie möglich zurückgeben, damit der Stapel von der temporären Konvertierung befreit wird.

TarmoPikaro
quelle
1

String zu 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 zu 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);
}
Isma Rekathakusuma
quelle
1
Diese Str2Wstr hat ein Problem mit der 0-Terminierung. Es ist nicht mehr möglich, die generierten Zeichenfolgen über "+" zu verketten (wie in Zeichenfolge s3 = s1 + s2). Ich werde bald eine Antwort veröffentlichen, um dieses Problem zu lösen. Müssen zuerst einige Tests auf Speicherlecks durchführen.
thewhiteambit
-2

string s = "おはよう"; ist ein Fehler.

Sie sollten wstring direkt verwenden:

wstring ws = L"おはよう";
Thomas Bonini
quelle
1
Das wird auch nicht funktionieren. Sie müssen diese Nicht-BMP-Zeichen in C-Escape-Sequenzen konvertieren.
Dave Van den Eynde
3
@ Dave: Es funktioniert, wenn Ihr Compiler Unicode in Quelldateien unterstützt, und alle im letzten Jahrzehnt (Visual Studio, GCC, ...)
Thomas Bonini
Hallo, unabhängig von der Standard-Systemcodierung (ich kann beispielsweise Arabisch als Standard-Systemcodierung verwenden), wie sollte die Codierung der Quellcodedatei für L "お は よ う" funktionieren? sollte es in UTF-16 sein, oder kann ich UTF-8 ohne Stückliste für die CPP-Dateicodierung haben?
Afriza N. Arief
2
@afriza: Es ist nicht wirklich wichtig, solange Ihre Kompilierung es unterstützt
Thomas Bonini
2
Es ist kein Fehler; Erweiterte Zeichen in einer "schmalen" Zeichenfolge werden definiert, um Multibyte-Sequenzen zuzuordnen. Der Compiler sollte es unterstützen, solange das Betriebssystem dies tut. Dies ist das Mindeste, was Sie fragen können.
Potatoswatter
-2

Verwenden Sie diesen Code, um Ihren String in wstring zu konvertieren

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;
}
Jaguar
quelle
3
Beachten Sie, dass in der Frage Windows nicht erwähnt wird und diese Antwort nur für Windows gilt.
Johann Gerell
CP_ACPist mit Sicherheit das falsche Argument. Der Umgebungsstatus des ausführenden Threads wirkt sich plötzlich auf das Verhalten des Codes aus. Nicht ratsam. Geben Sie bei Ihrer Konvertierung eine feste Zeichenkodierung an. (Und erwägen Sie, Fehler zu behandeln.)
Unsichtbarer