C ++ Converter string (ou char *) em wstring (ou wchar_t *)


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

Como eu atribuiria o conteúdo de s a ws?

Pesquisou no Google e usou algumas técnicas, mas elas não podem atribuir o conteúdo exato. O conteúdo está distorcido.


7
Eu não acho que stringsaceite caracteres de 8 bits. Já está codificado em UTF-8?
— Kennytm

3
Qual é a codificação do seu sistema para criar "おはよう"uma string codificada pelo sistema?
— SBI

Acredito que o MSVC aceite isso e faça uma codificação multibyte, talvez UTF-8.
— Potatoswatter

1
@ Potatoswatter: MSVC não usa UTF-8 por padrão para QUALQUER COISA. Se você inserir esses personagens, ele pede que a codificação para converter o arquivo para, e o padrão é página de código 1252.
— Mooing Duck

2
@ Samir: mais importante é o que é a codificação do arquivo ? Você pode mover essa sequência para o início do arquivo e mostrar um hexdump dessa parte? Provavelmente, podemos identificar isso a partir disso.
— Mooing Duck

Respostas:


239

Supondo que a string de entrada no seu exemplo (お は よ う) seja codificada em UTF-8 (o que não é, pelo que parece, mas vamos assumir que seja por causa desta explicação :-)) de uma string Unicode de seu interesse, seu problema poderá ser totalmente resolvido apenas com a biblioteca padrão (C ++ 11 e mais recente).

A versão 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);

Exemplo compilável e executável online mais longo:

(Todos mostram o mesmo exemplo. Existem muitos para redundância ...)

Nota (antiga) :

Conforme apontado nos comentários e explicado em https://stackoverflow.com/a/17106065/6345, há casos em que o uso da biblioteca padrão para converter entre UTF-8 e UTF-16 pode gerar diferenças inesperadas nos resultados em diferentes plataformas . Para uma melhor conversão, considere std::codecvt_utf8o descrito em http://en.cppreference.com/w/cpp/locale/codecvt_utf8

Nota (nova) :

Como o codecvtcabeçalho foi descontinuado no C ++ 17, foram levantadas algumas preocupações com a solução apresentada nesta resposta. No entanto, o comitê de padrões do C ++ adicionou uma declaração importante em http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html dizendo

esse componente da biblioteca deve ser retirado do anexo D, ao lado, até que uma substituição adequada seja padronizada.

Portanto, no futuro próximo, a codecvtsolução nesta resposta é segura e portátil.


2
Verifique o que você codificar salvar arquivos VS com
— Johann Gerell

9
Esteja ciente de que este é apenas C ++ 11!
— bk138

1
No minGW (gcc / g ++ 4.8.1 e -std = c ++ 11), o cabeçalho codecvt não existe. Existe uma alternativa?
— Brian Jack

1
Por favor, forneça um exemplo std::codecvt_utf8para iniciantes
— Noitidart 23/02

15
Observe que <codecvt>está obsoleto desde o 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
Isso funciona apenas se todos os caracteres tiverem um byte único, ou seja, ASCII ou ISO-8859-1 . Qualquer coisa com vários bytes falhará miseravelmente, incluindo o UTF-8. A pergunta contém claramente caracteres de vários bytes.
— Mark Ransom

28
Essa resposta é claramente insuficiente e não faz nada além de copiar caracteres estreitos como em caracteres largos. Veja as outras respostas, particularmente a de Johann Gerell, para saber como passar corretamente de uma sequência de caracteres de bytes múltiplos ou utf8 para uma sequência utf16.
— DLRdave

10
essa resposta é perigosa e provavelmente será interrompida no sistema não-ascii. ou seja, um nome de arquivo árabe será mutilado por esse hack.
— Stephen Stephen

9
Essa resposta é útil se você ignorar as nuances do corpo da pergunta e se concentrar no título da pergunta, que foi o que me trouxe aqui do Google. Como é, o título da pergunta é extremamente enganador e deve ser alterado para refletir a verdadeira pergunta que está sendo feita
— Anne Quinn

3
Isso funciona apenas para caracteres ASCII de 7 bits. Para latin1, ele funciona apenas se char estiver configurado como não assinado. Se o tipo char for assinado (o que geralmente ocorre), caracteres> 127 fornecerão resultados incorretos.
— huyc 16/05

32

Sua pergunta está subespecificada. Estritamente, esse exemplo é um erro de sintaxe. No entanto, std::mbstowcsé provavelmente o que você está procurando.

É uma função da biblioteca C e opera em buffers, mas aqui está um idioma fácil de usar, cortesia de TBohne (anteriormente 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 = novo wchar_t [s.size ()]; tamanho_t num_chars = mbstowcs (buf, s.c_str (), s.size ()); wstring ws (buf, num_chars); // ws = distorcido
— Samir

1
@ Samir: Você precisa garantir que a codificação em tempo de execução seja a mesma que a codificação em tempo de compilação. Pode ser necessário setlocaleou ajustar os sinalizadores do compilador. Não sei porque não uso o Windows, mas é por isso que não é um recurso comum. Considere a outra resposta, se possível.
— Potatoswatter 04/04

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

2
@WaffleSouffle Isso está desatualizado. Implementações contíguas são necessárias desde 2011 e as implementações encerram esses truques muito antes disso.
— Potatoswatter

1
e alguns ambientes como mingw ainda não têm o cabeçalho codecvt assim algumas das soluções 'melhores' mais cedo se não funcionam ou seja, este problema ainda não tem boas soluções em mingw mesmo em Dez 2014
— Brian Jack

18

Somente API do Windows, antes da implementação do C ++ 11, caso alguém precise:

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

Você pode otimizar isso. Não é necessário fazer cópia dupla da string usando a vector. Basta reservar os caracteres na string fazendo wstring strW(charsNeeded + 1);e, em seguida, usá-lo como tampão para a conversão: &strW[0]. Por último garantir última nula está presente após a conversão, fazendostrW[charsNeeded] = 0;
— C00000FD

1
@ c00000fd, tanto quanto eu sei, o buffer interno std :: basic_string precisa ser contínuo apenas desde o padrão C ++ 11. Meu código é anterior ao C ++ 11, conforme observado na parte superior da postagem. Portanto, o código & strW [0] não seria compatível com o padrão e poderá travar legitimamente no tempo de execução.
— 18780 Alex

13

Se você estiver usando o Windows / Visual Studio e precisar converter uma string em wstring, poderá usar:

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

O mesmo procedimento para converter uma string para string (às vezes você precisará especificar uma página de código ):

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

Você pode especificar uma página de código e até UTF8 (isso é muito bom ao trabalhar com JNI / Java ). Uma maneira padrão de converter um std :: wstring em utf8 std :: string é mostrada nesta resposta .

// 
// 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 você quiser saber mais sobre páginas de código, há um artigo interessante sobre Joel no Software: O Mínimo Absoluto Todo desenvolvedor de software deve saber absolutamente, positivamente, positivamente sobre Unicode e conjuntos de caracteres .

Essas macros CA2W (Converter ANSI para Wide = unicode) fazem parte das macros de conversão de string ATL e MFC , incluindo exemplos.

Às vezes, você precisará desativar o aviso de segurança # 4995 ', não conheço outra solução alternativa (isso acontece quando eu compilei o WindowsXp no VS2012).

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

Edit: Bem, de acordo com este artigo, o artigo de Joel parece ser: "embora divertido, é bastante claro sobre detalhes técnicos reais". Artigo: O que todo programador precisa absolutamente e positivamente de saber sobre codificação e conjuntos de caracteres para trabalhar com texto .


Desculpe, eu não sou um falante nativo de inglês. Edite como achar melhor.
— lmiguelmh

O que há com o downvoter? O que há de errado com a resposta?
— Lmiguelmh

Provavelmente, o fato de promover código não portátil.
— Pavel Minaev 24/08/2015

Sim, foi por isso que afirmei que isso funciona apenas no Windows / Visual Studio. Mas, pelo menos, esta solução é correta, e não um presente:char* str = "hello worlddd"; wstring wstr (str, str+strlen(str));
— lmiguelmh

Nota adicional: CA2W está no espaço de nome do ATL. (ATL :: CA2W)
— Val

12

Aqui está uma maneira de combinar string, wstringe constantes de cadeia mista para wstring. Use a wstringstreamclasse.

Isso NÃO funciona para codificações de caracteres de vários bytes. Esta é apenas uma maneira idiota de jogar fora a segurança de tipo e expandir os caracteres de 7 bits do std :: string para os 7 bits inferiores de cada caractere do std: wstring. Isso só é útil se você tiver uma sequência ASCII de 7 bits e precisar chamar uma API que exija uma sequência ampla.

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

A resposta parece interessante. Você poderia explicar um pouco: isso funcionará para codificações de vários bytes e por que / como?
— wh1t3cat1k

esquemas de codificação são ortogonais à classe de armazenamento. stringarmazena caracteres de 1 byte e wstringarmazena caracteres de 2 bytes. algo como utf8 armazena caracteres de vários bytes como uma série de valores de 1 byte, ou seja, em a string. as classes de string não ajudam na codificação. Eu não sou um especialista em codificar classes em c ++.
— Mark Lakata

2
Alguma razão para que essa não seja a melhor resposta, dada a curta e simples? Algum caso que não cobre?
— Ryuu

@ MarkLakata, li sua resposta ao primeiro comentário, mas ainda não tenho certeza. Funcionará para caracteres de vários bytes? Em outras palavras, não é propenso à mesma armadilha que esta resposta ?
— precisa saber é o seguinte

@ Marc.2377 Isso NÃO funciona para codificações de caracteres de vários bytes. Esta é apenas uma maneira idiota de jogar fora a segurança de tipo e expandir os caracteres de std::string7 bits dos 7 bits inferiores de cada caractere std:wstring. Isso é útil apenas se você tiver uma sequência ASCII de 7 bits e precisar chamar uma API que exija uma sequência ampla. Veja stackoverflow.com/a/8969776/3258851 se precisar de algo mais sofisticado.
— Mark Lakata

11

De char*para wstring:

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

De stringpara wstring:

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

Observe que isso só funciona bem se a sequência que está sendo convertida contiver apenas caracteres ASCII.


7
Porque isso só funciona se a codificação for Windows-1252, que nem pode conter as letras da pergunta.
— Mooing Duck

3
essa é a maneira menos propensa a erros quando você sabe que está lidando com ASCII. Esse é um caso de uso proeminente ao portar aplicativos para APIs mais recentes.
— Sid Sarasvati

Este não é o caminho. Se você estiver usando o Visual Studio, use atlconv.h. Verifique as outras respostas.
— Lmiguelmh

7

usando Boost.Locale:

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

5

Essa variante é a minha favorita na vida real. Ele converte a entrada, se for UTF-8 válido , na respectiva wstring. Se a entrada estiver corrompida, ela wstringserá construída a partir dos bytes únicos. Isso é extremamente útil se você realmente não tiver certeza da qualidade dos seus dados de entrada.

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
Eu só lançou esta pergunta com base em sua resposta stackoverflow.com/questions/49669048/... você pode gentilmente dar uma olhada
— MistyD

2

Se você tem QT e tem preguiça de implementar uma função e outras coisas, pode usar

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


Quase, mas você deve começar com a QString, porque o QStringconstrutor não pode aceitar uma string por algum motivo.
— bobsbeenjamin


Isso é legal. Além disso, você pode usar .c_str () para permitir que o QString aceite sua string no construtor.
— miep 01/07

1

O método s2ws funciona bem. A esperança ajuda.

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
O que há com todas essas respostas alocando memória dinâmica de maneira insegura e copiando os dados do buffer para a string? Por que ninguém se livra do intermediário inseguro?
— Mooing Duck

hahakubile, você pode ajudar por favor com algo semelhante para o ws2s?
— cristian

1

Com base nos meus próprios testes (no Windows 8, vs2010), o mbstowcs pode danificar a string original, funciona apenas com a página de código ANSI. Se MultiByteToWideChar / WideCharToMultiByte também puder causar corrupção de string - mas eles tendem a substituir caracteres que não conhecem por '?' pontos de interrogação, mas o mbstowcs tende a parar quando encontra caracteres desconhecidos e corta a corda nesse exato momento. (Eu testei caracteres vietnamitas em janelas finlandesas).

Portanto, prefira a função api da Multi-windows em vez das funções analógicas ansi C.

Além disso, o que eu notei que a maneira mais curta de codificar string de uma página de código para outra não é usar as funções de API api da MultiByteToWideChar / WideCharToMultiByte, mas suas macros analógicas ATL: W2A / A2W.

Portanto, a função analógica, como mencionado acima, soa como:

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

_acp é declarado na macro USES_CONVERSION.

Ou também a função que frequentemente sinto falta ao realizar a conversão de dados antigos para um novo:

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

   _acp = CP_UTF8;
   return W2A( pw );
}

Mas observe que essas macro usam muito a pilha - não use para loops ou loops recursivos para a mesma função - depois de usar a macro W2A ou A2W - é melhor retornar o mais rápido possível, para que a pilha seja liberada da conversão temporária.


1

String para 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 para 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
Este Str2Wstr tem um problema com a terminação 0. Não é possível concatenar mais as seqüências de caracteres geradas via "+" (como na sequência de caracteres s3 = s1 + s2). Vou postar uma resposta em breve resolvendo esse problema. Primeiro, é necessário testar alguns vazamentos de memória.
— thewhiteambit

-2

string s = "おはよう"; é um erro.

Você deve usar o wstring diretamente:

wstring ws = L"おはよう";

1
Isso também não vai funcionar. Você precisará converter esses caracteres não-BMP em seqüências de escape em C.
— Dave Van den Eynde 04/04

3
@ Dave: ela não funciona se suas sustentações do compilador Unicode em arquivos de origem, e todos os da última década fazer (visual studio, gcc, ...)
— Thomas Bonini

Olá, independentemente da codificação padrão do sistema (posso ter o árabe como codificação padrão do sistema, por exemplo), qual deve ser a codificação do arquivo de código-fonte para L "お は よ う" funcionar? deveria estar em UTF-16 ou posso ter UTF-8 sem BOM para a codificação de arquivo .cpp?
— Afriza N. Arief 12/08

2
@afriza: isso realmente não importa, contanto que seus apoios compilá-lo
— Thomas Bonini

2
Não é um erro; caracteres estendidos em uma cadeia "estreita" são definidos para mapear para seqüências multibyte. O compilador deve suportá-lo desde que o sistema operacional o faça, o mínimo que você pode pedir.
— Potatoswatter

-2

use esse código para converter sua string em 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
Observe que a pergunta não menciona o Windows e esta resposta é somente para Windows.
— Johann Gerell 27/08/2015

CP_ACPé certamente o argumento errado. De repente, o estado do ambiente do encadeamento em execução afeta o comportamento do código. Não aconselhável. Especifique uma codificação de caracteres fixa na sua conversão. (E considere o tratamento de erros.)
— IInspectable
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.