C ++ Converti stringa (o char *) in wstring (o wchar_t *)


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

Come assegnerei il contenuto di s a ws?

Hanno cercato su Google e utilizzato alcune tecniche ma non possono assegnare il contenuto esatto. Il contenuto è distorto.


7
Non credo che stringsaccetta caratteri a 8 bit. È già codificato in UTF-8?
— kennytm,

3
Qual è la tua codifica di sistema per creare "おはよう"una stringa con codifica di sistema?
— sbi,

Credo che MSVC lo accetti e ne faccia una codifica multibyte, forse UTF-8.
— Potatoswatter

1
@Potatoswatter: MSVC non utilizza UTF-8 per impostazione predefinita per ANYTHING. Se si immettono quei caratteri, viene richiesta la codifica in cui convertire il file e viene impostata automaticamente la tabella codici 1252.
— Mooing Duck

2
@Samir: più importante è la codifica del file ? Puoi spostare quella stringa all'inizio del file e mostrare un dump esadecimale di quella parte? Probabilmente possiamo identificarlo da quello.
— Mooing Duck,

Risposte:


239

Supponendo che la stringa di input nel tuo esempio (お は よ う) sia una codifica UTF-8 (che non è, a quanto pare, ma supponiamo che sia per il bene di questa spiegazione :-)) rappresentazione di una stringa Unicode di tuo interesse, quindi il tuo problema può essere risolto completamente con la sola libreria standard (C ++ 11 e successive).

La versione 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);

Esempio compilabile e eseguibile online più lungo:

(Tutti mostrano lo stesso esempio. Ce ne sono solo molti per la ridondanza ...)

Nota (vecchia) :

Come sottolineato nei commenti e spiegato in https://stackoverflow.com/a/17106065/6345 ci sono casi in cui l'uso della libreria standard per la conversione tra UTF-8 e UTF-16 potrebbe dare differenze inaspettate nei risultati su piattaforme diverse . Per una migliore conversione, considerare std::codecvt_utf8come descritto su http://en.cppreference.com/w/cpp/locale/codecvt_utf8

Nota (nuova) :

Poiché l' codecvtintestazione è obsoleta in C ++ 17, sono state sollevate alcune preoccupazioni in merito alla soluzione presentata in questa risposta. Tuttavia, il comitato per gli standard C ++ ha aggiunto una dichiarazione importante in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html dicendo

questo componente della biblioteca dovrebbe essere ritirato all'allegato D, a fianco, fino a quando non viene standardizzata una sostituzione adeguata.

Quindi, nel prossimo futuro, la codecvtsoluzione in questa risposta è sicura e portatile.


2
Controlla con quale codifica salvi i file VS
— Johann Gerell

9
Ricorda che questo è solo C ++ 11!
— bk138,

1
In minGW (gcc / g ++ 4.8.1 e -std = c ++ 11) l'intestazione codecvt non esiste. C'è un'alternativa?
— Brian Jack,

1
std::codecvt_utf8
— Potresti

15
Si noti che <codecvt>è obsoleto dal C ++ 17.
— tambre,

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

    ws = wsTmp;

    return 0;
}

93
Funziona solo se tutti i caratteri sono a byte singolo, ovvero ASCII o ISO-8859-1 . Qualsiasi cosa a più byte fallirà miseramente, incluso UTF-8. La domanda contiene chiaramente caratteri multibyte.
— Mark Ransom,

28
Questa risposta è chiaramente insufficiente e non fa altro che copiare caratteri stretti come in caratteri ampi. Vedi le altre risposte, in particolare quella di Johann Gerell, su come passare correttamente da una stringa codificata multi-byte o utf8 a una stringa utf16.
— DLRdave,

10
questa risposta è pericolosa e probabilmente si interromperà su un sistema non ASCII. cioè un nome di file arabo sarà rovinato da questo hack.
— Stephen,

9
Questa risposta è utile se ignori la sfumatura del corpo della domanda e ti concentri sul titolo della domanda, che è ciò che mi ha portato qui da Google. Così com'è, il titolo della domanda è estremamente fuorviante e dovrebbe essere modificato per riflettere la vera domanda posta
— Anne Quinn,

3
Funziona solo con caratteri ASCII a 7 bit. Per latin1, funziona solo se char è configurato come unsigned. Se il carattere char è firmato (che è il più delle volte il caso), i caratteri> 127 daranno risultati errati.
— huyc,

32

La tua domanda non è specificata In senso stretto, questo esempio è un errore di sintassi. Tuttavia, std::mbstowcsè probabilmente quello che stai cercando.

È una funzione C-library e opera su buffer, ma ecco un linguaggio facile da usare, per gentile concessione di TBohne (precedentemente 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 = distorto
— Samir

1
@Samir: devi assicurarti che la codifica di runtime sia la stessa della codifica in fase di compilazione. Potrebbe essere necessario setlocaleo modificare i flag del compilatore. Non lo so perché non utilizzo Windows, ma è per questo che non è una funzionalità comune. Considera l'altra risposta, se possibile.
— Potatoswatter

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

2
@WaffleSouffle Non è aggiornato. Dal 2011 sono richieste implementazioni contigue e le implementazioni hanno abbandonato tali trucchi molto prima.
— Potatoswatter,

1
e alcuni ambienti come mingw non hanno ancora l'intestazione codecvt, quindi alcune delle soluzioni "migliori" precedenti non funzionano, il che significa che questo problema non ha ancora buone soluzioni a mingw anche a partire da dicembre 2014
— Brian Jack,

18

Solo API Windows, implementazione pre C ++ 11, nel caso qualcuno ne abbia bisogno:

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

Puoi ottimizzarlo. Non è necessario eseguire una doppia copia della stringa utilizzando a vector. Basta prenotare i caratteri della stringa da fare wstring strW(charsNeeded + 1);e quindi utilizzarlo come buffer per la conversione: &strW[0]. Infine assicurati che sia presente l'ultimo null dopo la conversione facendostrW[charsNeeded] = 0;
— c00000fd

1
@ c00000fd, per quanto ne so, il buffer interno std :: basic_string deve essere continuo solo dallo standard C ++ 11. Il mio codice è pre-C ++ 11, come indicato nella parte superiore del post. Pertanto, il codice & strW [0] non sarebbe conforme allo standard e potrebbe arrestarsi in modo legittimo in fase di esecuzione.
— Alex Che

13

Se stai usando Windows / Visual Studio e devi convertire una stringa in wstring puoi usare:

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

Stessa procedura per convertire una stringa in stringa (a volte è necessario specificare una tabella codici ):

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

È possibile specificare una tabella codici e persino UTF8 (che è piuttosto carino quando si lavora con JNI / Java ). In questa risposta viene mostrato un modo standard per convertire una stringa std :: wstring in utf8 std :: stringa .

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

Se vuoi saperne di più sui codici, c'è un interessante articolo su Joel on Software: il minimo assoluto che ogni sviluppatore di software deve assolutamente conoscere positivamente su Unicode e set di caratteri .

Queste macro CA2W (Converti Ansi in Wide = unicode) fanno parte delle macro di conversione stringhe ATL e MFC , inclusi gli esempi.

A volte dovrai disabilitare l'avviso di sicurezza # 4995 ', non conosco altre soluzioni alternative (a me succede quando ho compilato per WindowsXp in VS2012).

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

Modifica: Beh, secondo questo articolo l'articolo di Joel sembra essere: "mentre è divertente, è abbastanza leggero sui dettagli tecnici reali". Articolo: Ciò che ogni programmatore deve assolutamente e positivamente sapere sulla codifica e sui set di caratteri per lavorare con il testo .


Mi dispiace non sono un madrelingua inglese. Modifica come ritieni opportuno.
— lmiguelmh,

Cosa succede con il downvoter? Cosa c'è di sbagliato nella risposta?
— lmiguelmh,

Probabilmente il fatto che promuove il codice non portatile.
— Pavel Minaev,

Sì, ecco perché ho affermato che funziona solo in Windows / Visual Studio. Ma almeno questa soluzione è corretta, e non questa:char* str = "hello worlddd"; wstring wstr (str, str+strlen(str));
— lmiguelmh,

Nota aggiuntiva: CA2W si trova nello spazio dei nomi di ATL. (ATL :: CA2W)
— Val

12

Ecco un modo di combinare string, wstringe costanti stringa misti a wstring. Usa la wstringstreamclasse.

Questo NON funziona per le codifiche di caratteri multi-byte. Questo è solo un modo stupido di gettare via la sicurezza del tipo ed espandere i caratteri a 7 bit da std :: string nei 7 bit inferiori di ogni carattere di std: wstring. Ciò è utile solo se si dispone di stringhe ASCII a 7 bit e è necessario chiamare un'API che richiede stringhe estese.

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

La risposta sembra interessante. Potresti spiegare un po ': funzionerà per le codifiche multi-byte e perché / come?
— wh1t3cat1k,

gli schemi di codifica sono ortogonali alla classe di archiviazione. stringmemorizza i caratteri da 1 byte e wstringmemorizza i caratteri da 2 byte. qualcosa come utf8 memorizza i caratteri mulitbyte come una serie di valori di 1 byte, cioè in a string. le classi di stringhe non aiutano con la codifica. Non sono un esperto di codifica delle classi in c ++.
— Mark Lakata,

2
Qualche motivo per cui questa non è la risposta migliore, dato quanto è breve e semplice? Qualche caso che non copre?
— Ryuu,

@MarkLakata, ho letto la tua risposta al primo commento ma non sono ancora sicuro. Funzionerà con caratteri multibyte? In altre parole, non è incline alla stessa trappola di questa risposta ?
— Marc.2377,

@ Marc.2377 Questo NON funziona per le codifiche di caratteri multi-byte. Questo è solo un modo stupido di gettare via la sicurezza del tipo ed espandere i caratteri std::stringa 7 bit nei 7 bit inferiori di ogni carattere di std:wstring. Ciò è utile solo se si dispone di stringhe ASCII a 7 bit e è necessario chiamare un'API che richiede stringhe estese. Guarda stackoverflow.com/a/8969776/3258851 se hai bisogno di qualcosa di più sofisticato.
— Mark Lakata,

11

Da char*a wstring:

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

Da stringa wstring:

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

Nota che funziona bene solo se la stringa da convertire contiene solo caratteri ASCII.


7
Perché questo funziona solo se la codifica è Windows-1252, che non può nemmeno contenere le lettere nella domanda.
— Mooing Duck

3
questo è il modo meno propenso per farlo, quando sai che hai a che fare con ASCII. Che è un caso d'uso importante quando si esegue il porting di app su API più recenti.
— Sid Sarasvati,

Questo è non è il modo. Se si utilizza Visual Studio, è necessario utilizzare atlconv.h. Controlla le altre risposte.
— lmiguelmh,

7

utilizzando Boost.Locale:

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

5

Questa variante è la mia preferita nella vita reale. Converte l'ingresso, se è UTF-8 valido , nel rispettivo wstring. Se l'input è danneggiato, wstringviene costruito dai singoli byte. Questo è estremamente utile se non puoi davvero essere sicuro della qualità dei tuoi dati di input.

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
Ho appena lanciato questa domanda in base alla tua risposta stackoverflow.com/questions/49669048/… puoi gentilmente dare un'occhiata
— MistyD

2

Se hai QT e se sei pigro per implementare una funzione e cose che puoi usare

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


Quasi, ma dovresti semplicemente iniziare con a QString, perché il QStringcostruttore non può accettare una stringa per qualche motivo.
— bobsbeenjamin,


Questo è carino. Inoltre, puoi usare .c_str () per consentire a QString di accettare la tua stringa nel costruttore.
— miep

1

il metodo s2ws funziona bene. La speranza aiuta.

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
Che cosa succede con tutte queste risposte allocare la memoria dinamica in modo non sicuro e quindi copiare i dati dal buffer alla stringa? Perché nessuno si libera del mediatore insicuro?
— Mooing Duck

hahakubile, puoi aiutare per favore con qualcosa di simile per ws2s?
— cristian,

1

Basato sul mio test (su Windows 8, vs2010) mbstowcs può effettivamente danneggiare la stringa originale, funziona solo con la tabella codici ANSI. Se MultiByteToWideChar / WideCharToMultiByte può anche causare il danneggiamento delle stringhe, ma tendono a sostituire i caratteri che non conoscono con "?" punti interrogativi, ma mbstowcs tende a fermarsi quando incontra un carattere sconosciuto e taglia la stringa proprio in quel punto. (Ho testato personaggi vietnamiti su finestre finlandesi).

Quindi preferisci la funzione API * Multi-windows rispetto alle funzioni analogiche C.

Inoltre, ciò che ho notato il modo più breve per codificare la stringa da una tabella codici a un'altra non è usare le chiamate della funzione API MultiByteToWideChar / WideCharToMultiByte ma i loro macro ATL analogici: W2A / A2W.

Quindi la funzione analogica sopra menzionata suona come:

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

_acp è dichiarato nella macro USES_CONVERSION.

O anche la funzione che spesso mi manca quando eseguo la conversione di dati vecchi in uno nuovo:

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

   _acp = CP_UTF8;
   return W2A( pw );
}

Ma tieni presente che quelle macro usano pesantemente lo stack - non utilizzare per loop o loop ricorsivi per la stessa funzione - dopo aver usato macro W2A o A2W - meglio per restituire al più presto, quindi lo stack verrà liberato dalla conversione temporanea.


1

Stringa a filo

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 a 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
Questo Str2Wstr ha un problema con terminazione 0. Non è più possibile concatenare i wstring generati tramite "+" (come in wstring s3 = s1 + s2). Invierò presto una risposta per risolvere questo problema. Prima devi fare alcuni test per le perdite di memoria.
— thewhiteambit

-2

string s = "おはよう"; è un errore.

Dovresti usare direttamente wstring:

wstring ws = L"おはよう";

1
Neanche questo funzionerà. Dovrai convertire quei caratteri non BMP in sequenze di escape C.
— Dave Van den Eynde,

3
@Dave: funziona se il tuo compilatore supporta unicode nei file sorgente, e tutti quelli dell'ultimo decennio lo fanno (visual studio, gcc, ...)
— Thomas Bonini

Salve, indipendentemente dalla codifica di sistema predefinita (ad esempio, potrei avere l'arabo come codifica di sistema predefinita), come dovrebbe funzionare la codifica del file di codice sorgente per L "お は よ う"? dovrebbe essere in UTF-16 o posso avere UTF-8 senza BOM per la codifica del file .cpp?
— Afriza N. Arief,

2
@afriza: non importa se la tua compilazione lo supporta
— Thomas Bonini,

2
Non è un errore; i caratteri estesi in una stringa "stretta" sono definiti per mappare a sequenze multibyte. Il compilatore dovrebbe supportarlo fino a quando lo fa il sistema operativo, che è il minimo che puoi chiedere.
— Potatoswatter,

-2

usa questo codice per convertire la stringa in 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
Nota che la domanda non menziona Windows e questa risposta è solo Windows.
— Johann Gerell,

CP_ACPè sicuramente l'argomento sbagliato. Improvvisamente, lo stato dell'ambiente del thread in esecuzione ha un effetto sul comportamento del codice. Non consigliabile. Specifica una codifica a caratteri fissi nella conversione. (E considerare la gestione degli errori.)
— Indispensabile il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.