¿Es posible convertir cadenas UTF8 en std :: string a std :: wstring y viceversa de una manera independiente de plataforma? En una aplicación de Windows usaría MultiByteToWideChar y WideCharToMultiByte. Sin embargo, el código está compilado para múltiples sistemas operativos y estoy limitado a la biblioteca estándar de C++.UTF8 a/desde conversión de ancho de pila en STL
Respuesta
Puede usar el codecvt
locale facet. Hay una especialización específica definida, codecvt<wchar_t, char, mbstate_t>
que puede ser útil para usted, aunque el comportamiento de eso es específico del sistema y no garantiza la conversión a UTF-8 de ninguna manera.
Hacer la codificación/decodificación según la configuración regional es una mala idea. Tal como dijiste: "no garantiza". –
@TylerLong, obviamente, uno debe configurar la instancia de std :: locale específicamente para la conversión requerida. – Basilevs
@Basilevs Sigo pensando que utilizar la configuración regional para codificar/decodificar es incorrecto. La forma correcta es configurar 'encoding' en lugar de' locale'. Por lo que puedo decir, no existe una localización tal que pueda representar ** cada ** único carácter Unicode. Digamos que quiero codificar una cadena que contenga todos los caracteres Unicode, ¿qué entorno me sugieres que configure? Arrántrame si estoy equivocado –
No creo que haya una forma portátil de hacerlo. C++ no conoce la codificación de sus caracteres multibyte.
Como sugirió Chris, su mejor opción es jugar con codecvt.
La pregunta dice "UTF8", por lo que "la codificación de sus caracteres multibyte" es conocida. –
Puede extraer utf8_codecvt_facet
de Boost serialization library.
Su ejemplo de uso:
typedef wchar_t ucs4_t;
std::locale old_locale;
std::locale utf8_locale(old_locale,new utf8_codecvt_facet<ucs4_t>);
// Set a New global locale
std::locale::global(utf8_locale);
// Send the UCS-4 data out, converting to UTF-8
{
std::wofstream ofs("data.ucd");
ofs.imbue(utf8_locale);
std::copy(ucs4_data.begin(),ucs4_data.end(),
std::ostream_iterator<ucs4_t,ucs4_t>(ofs));
}
// Read the UTF-8 data back in, converting to UCS-4 on the way in
std::vector<ucs4_t> from_file;
{
std::wifstream ifs("data.ucd");
ifs.imbue(utf8_locale);
ucs4_t item = 0;
while (ifs >> item) from_file.push_back(item);
}
Busque utf8_codecvt_facet.hpp
y utf8_codecvt_facet.cpp
archivos de fuentes de impulso.
Pensé que tenía que imbuir la secuencia antes de abrirla, de lo contrario, se ignora el imbue. –
Martin, parece funcionar con Visual Studio 2005: 0x41a se convierte satisfactoriamente a la secuencia {0xd0, 0x9a} UTF-8. – Constantin
Existen varias formas de hacerlo, pero los resultados dependen de las codificaciones de los caracteres en las variables string
y wstring
.
Si conoce la string
es ASCII, sólo tiene que utilizar el constructor iterador wstring
's:
string s = "This is surely ASCII.";
wstring w(s.begin(), s.end());
Si su string
tiene alguna otra codificación, sin embargo, obtendrá resultados muy malos. Si la codificación es Unicode, puede echarle un vistazo al ICU project, que proporciona un conjunto de bibliotecas multiplataforma que convierte desde y hacia todo tipo de codificaciones Unicode.
Si su string
contiene caracteres en una página de códigos, entonces puede $ DEITY tener piedad de su alma.
ICU se convierte también/de cada codificación de caracteres que he encontrado. Es enorme. –
La definición del problema establece explícitamente que la codificación de caracteres de 8 bits es UTF-8. Eso hace que esto sea un problema trivial; todo lo que requiere es un poco de tiempo para convertir una especificación UTF a otra.
Solo mira las codificaciones en estas páginas de Wikipedia para UTF-8, UTF-16 y UTF-32.
El principio es simple: revise la entrada y ensamble un punto de código Unicode de 32 bits según una especificación UTF, luego emita el punto de código de acuerdo con la otra especificación. Los puntos de código individuales no necesitan traducción, como se requeriría con cualquier otra codificación de caracteres; eso es lo que hace que esto sea un problema simple.
Aquí hay una implementación rápida de wchar_t
para la conversión UTF-8 y viceversa. Asume que la entrada ya está codificada correctamente; aquí se aplica el viejo dicho "Basura adentro, basura afuera". Creo que verificar la codificación se realiza mejor como un paso separado.
std::string wchar_to_UTF8(const wchar_t * in)
{
std::string out;
unsigned int codepoint = 0;
for (in; *in != 0; ++in)
{
if (*in >= 0xd800 && *in <= 0xdbff)
codepoint = ((*in - 0xd800) << 10) + 0x10000;
else
{
if (*in >= 0xdc00 && *in <= 0xdfff)
codepoint |= *in - 0xdc00;
else
codepoint = *in;
if (codepoint <= 0x7f)
out.append(1, static_cast<char>(codepoint));
else if (codepoint <= 0x7ff)
{
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else if (codepoint <= 0xffff)
{
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else
{
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
codepoint = 0;
}
}
return out;
}
El código anterior funciona tanto para la entrada UTF-16 y UTF-32, simplemente porque la gama d800
través de dfff
son puntos de código no válido; indican que está decodificando UTF-16. Si sabe que wchar_t
es de 32 bits, entonces podría eliminar algún código para optimizar la función.
std::wstring UTF8_to_wchar(const char * in)
{
std::wstring out;
unsigned int codepoint;
while (*in != 0)
{
unsigned char ch = static_cast<unsigned char>(*in);
if (ch <= 0x7f)
codepoint = ch;
else if (ch <= 0xbf)
codepoint = (codepoint << 6) | (ch & 0x3f);
else if (ch <= 0xdf)
codepoint = ch & 0x1f;
else if (ch <= 0xef)
codepoint = ch & 0x0f;
else
codepoint = ch & 0x07;
++in;
if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
{
if (sizeof(wchar_t) > 2)
out.append(1, static_cast<wchar_t>(codepoint));
else if (codepoint > 0xffff)
{
out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
}
else if (codepoint < 0xd800 || codepoint >= 0xe000)
out.append(1, static_cast<wchar_t>(codepoint));
}
}
return out;
}
Una vez más si sabe que wchar_t
es de 32 bits que podría quitar algo de código de esta función, pero en este caso no debe hacer ninguna diferencia. La expresión sizeof(wchar_t) > 2
es conocida en tiempo de compilación, por lo que cualquier compilador decente reconocerá el código muerto y lo eliminará.
No veo nada relacionado con std :: string que contenga cadenas codificadas en UTF-8 en la pregunta original: "¿Es posible convertir std :: string en std :: wstring y viceversa de una manera independiente de la plataforma?" –
UTF-8 se especifica en el título de la publicación. Tiene razón en que falta en el cuerpo del texto. –
Doh, tienes razón. UTF8-CPP luego :) –
crédito a bames53 para proporcionar versiones actualizadas
Se puede descargar desde [aquí] (http://www.koders.com/c/fid112E1609930ADAE7CA143040A834BAC0165DCD65.aspx?s=ConvertUTF.h) –
UTFConverter - echa un vistazo a esta biblioteca. Hace tal conversión, pero también necesita la clase ConvertUTF - Lo he encontrado here
Hace 5 años hice esta pregunta. Este hilo fue muy útil para mí en ese momento, llegué a una conclusión y luego continué con mi proyecto. Es gracioso que necesité algo similar recientemente, totalmente ajeno a ese proyecto del pasado. Mientras buscaba posibles soluciones, tropecé con mi propia pregunta :)
La solución que elegí ahora se basa en C++ 11. Las bibliotecas de impulso que menciona Constantin en his answer ahora son parte del estándar. Si reemplazamos std :: wstring con el nuevo std :: string tipo u16string, a continuación, las conversiones se vería así:
UTF-8 a UTF-16
std::string source;
...
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::u16string dest = convert.from_bytes(source);
UTF-16 a UTF-8
std::u16string source;
...
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::string dest = convert.to_bytes(source);
Como se ve en las otras respuestas, hay varios enfoques del problema. Es por eso que me abstengo de elegir una respuesta aceptada.
wstring implica 2 o 4 bytes en lugar de caracteres de un solo byte. ¿Dónde está la pregunta para cambiar de codificación utf8? –
Tengo un rendimiento pobremente extraño con codecvt, mira aquí para más detalles: http://stackoverflow.com/questions/26196686/utf8-utf16-codecvt-poor-performance –
Creo que deberías aceptar esta respuesta. Seguro que hay varias formas de resolver esto, pero esta es la única solución portátil que no necesita una biblioteca. – Navin
- 1. Conversión de UTF8 a ASCII
- 2. Conversión de latin1_swedish_ci a utf8 con PHP
- 3. Conversión de UTF8 a ANSI con Ruby
- 4. Uso de la pila definida en C++ stl
- 5. Conversión de caracteres UTF8 escapados a su forma original
- 6. ¿Cómo usar iconv para la conversión de utf8?
- 7. contenedores STL en la pila y el montón
- 8. codificación Java UTF8
- 9. conversión de ancho a partir del porcentaje de píxeles
- 10. de caracteres UTF8 decodificación en C Objetivo
- 11. C++ Pregunta de pila de STL: ¿Por qué pop() no lanza una excepción si la pila está vacía?
- 12. Ruby on Rails subir problema de los archivos UTF8 extraño error de conversión
- 13. Procesamiento UTF8 en C
- 14. Depuración de contenedores C++ STL en Windbg
- 15. Creación de objetos en la pila/pila?
- 16. C++ Pregunta STL: asignadores
- 17. C++: Almacenamiento de estructuras en una pila
- 18. Conversión de ostream en cadena estándar
- 19. ios Codificación UTF8 de nsstring
- 20. Conversión de codificación Eclipse
- 21. MySQL - Convertir caracteres latin1 en una mesa de UTF8 en UTF8
- 22. Buscando clase vector C++ STL-like pero usando almacenamiento de pila
- 23. Gráfico de barras de columna de pila de ancho específico Highchart
- 24. Estructuras de datos equivalentes de contenedores STL
- 25. ¿Cuál es el ancho de una pila en una arquitectura Intel IA32?
- 26. Stack STL con 2 params
- 27. Conversión de conjuntos de enteros en rangos
- 28. conversión de QString a char *
- 29. STL asignación de contenedores y punteros const
- 30. C# UTF8 Lectura/Salida
A propósito, la biblioteca estándar de C++ no se llama STL; el STL es solo una pequeña subsección de la biblioteca estándar de C++. En este caso, creo que está pidiendo funcionalidad en la biblioteca estándar de C++, y he respondido en consecuencia. –
No ha especificado con qué codificación desea terminar. wstring no especifica ninguna codificación particular. Por supuesto, sería natural convertir a utf32 en plataformas donde wchar_t tiene 4 bytes de ancho y utf16 si wchar_t tiene 2 bytes. ¿Es eso lo que quieres? – jalf