¿Cuál es la forma óptima multiplataforma de tratar con cadenas Unicode en C++?
string multiplatform (5)
Sé que ya hay varias preguntas en StackOverflow sobre std::string
versus std::wstring
o similar, pero ninguna de ellas propuso una solución completa.
Para obtener una buena respuesta debo definir los requisitos:
- Uso multiplataforma , debe funcionar en Windows, OS X y Linux.
- esfuerzo mínimo para la conversión a / desde cadenas Unicode específicas de la plataforma como
CFStringRef
,wchar_t *
,char*
como UTF-8 u otros tipos según lo requiera la API del sistema operativo. Nota: no necesito soporte de conversión de páginas de códigos porque espero usar solo las funciones compatibles con Unicode en todos los sistemas operativos compatibles. - Si requiere una biblioteca externa, esta debería ser de código abierto y con una licencia muy liberal como BSD pero no LGPL.
- Poder usar una sintaxis de formato printf o similar.
- forma fácil de asignación de cadenas / desasignación
- el rendimiento no es muy importante porque asumo que las cadenas Unicode se usan solo para la interfaz de usuario de la aplicación.
- algún ejemplo podría ser apreciado
Realmente apreciaría solo una solución propuesta por respuesta , al hacer esto, las personas pueden votar por su alternativa preferida. Si tiene más de una alternativa, simplemente agregue otra respuesta.
Por favor indique algo que funcionó para usted .
Preguntas relacionadas:
Hace poco estuve en un proyecto que decidió usar std :: wstring para un proyecto multiplataforma porque "las cadenas anchas son Unicode, ¿verdad?" Esto llevó a una serie de dolores de cabeza:
- ¿Qué tan grande es el valor escalar en una cuerda? Respuesta: Depende de la implementación del compilador. En Visual Studio (Win), es de 16 bits. Pero en Xcode (Mac), es de 32 bits.
- Esto condujo a una desafortunada decisión de usar UTF-16 para la comunicación por cable. ¿Pero cuál UTF-16? Hay dos: UTF-16BE (big-endian) y UTF16-LE (little-endian). No ser claro en esto llevó a más errores.
Cuando se encuentra en un código específico de la plataforma, tiene sentido utilizar la representación nativa de la plataforma para comunicarse con sus API. Pero para cualquier código que se comparta a través de plataformas, o que se comunique entre plataformas, evite toda ambigüedad y use UTF-8.
Igual que la respuesta de Adam Rosenfield (+1), pero en su lugar utilizo UTFCPP .
Iría para la representación de UTF16 en memoria y UTF-8 o 16 en disco duro o cable. La razón principal: UTF16 tiene un tamaño fijo para cada "letra". Esto simplifica una gran cantidad de tareas cuando se trabaja con la cadena (remachado, reemplazo de piezas, ...).
La única razón para UTF-8 es el uso reducido de la memoria para las letras "occidentales / latinas". Puede utilizar esta representación para el almacenamiento de discos o el transporte a través de la red. También tiene la ventaja de que no debe preocuparse por el orden de bytes al cargar / guardar en disco / cable.
Teniendo en cuenta estos motivos, optaría por std :: wstring internamente o, si su biblioteca de GUI ofrece un Widestring, utilícelo (como QString de QT). Y para el almacenamiento en disco, escribiría un pequeño contenedor de plataforma independiente para la plataforma api. O me gustaría visitar unicode.org si tienen un código independiente de plataforma disponible para esta conversión.
Para aclarar: las letras coreanas / japonesas NO son occidentales / latinas. Los japoneses son para ejpli kanji. Es por eso que mencioné el conjunto de caracteres latinos.
para UTF-16 no siendo 1 carácter / 2 bytes. Este supuesto solo es válido para los personajes que se encuentran en el plano multilingüe básico (consulte: http://en.wikipedia.org/wiki/UTF16 ). Aún así, la mayoría de los usuarios de UTF-16 asumen que todos los caracteres están en el BMP. Si esto no se puede garantizar para su aplicación, puede cambiar a UTF32 o a UTF8.
Todavía se usa UTF-16 por los motivos mencionados anteriormente en muchas API (por ejemplo, Windows, QT, Java, .NET, wxWidgets)
Recomendaría encarecidamente utilizar UTF-8 internamente en su aplicación, usar el antiguo char*
o std::string
normal para el almacenamiento de datos. Para interactuar con API que usan una codificación diferente (ASCII, UTF-16, etc.), recomiendo usar libiconv , que está licenciado bajo la licencia LGPL.
Ejemplo de uso:
class TempWstring
{
public:
TempWstring(const char *str)
{
assert(sUTF8toUTF16 != (iconv_t)-1);
size_t inBytesLeft = strlen(str);
size_t outBytesLeft = 2 * (inBytesLeft + 1); // worst case
mStr = new char[outBytesLeft];
char *outBuf = mStr;
int result = iconv(sUTF8toUTF16, &str, &inBytesLeft, &outBuf, &outBytesLeft);
assert(result == 0 && inBytesLeft == 0);
}
~TempWstring()
{
delete [] mStr;
}
const wchar_t *Str() const { return (wchar_t *)mStr; }
static void Init()
{
sUTF8toUTF16 = iconv_open("UTF-16LE", "UTF-8");
assert(sUTF8toUTF16 != (iconv_t)-1);
}
static void Shutdown()
{
int err = iconv_close(sUTF8toUTF16);
assert(err == 0);
}
private:
char *mStr;
static iconv_t sUTF8toUTF16;
};
iconv_t TempWstring::sUTF8toUTF16 = (iconv_t)-1;
// At program startup:
TempWstring::Init();
// At program termination:
TempWstring::Shutdown();
// Now, to convert a UTF-8 string to a UTF-16 string, just do this:
TempWstring x("Entr/xc3/xa9""e"); // "Entrée"
const wchar_t *ws = x.Str(); // valid until x goes out of scope
// A less contrived example:
HWND hwnd = CreateWindowW(L"class name",
TempWstring("UTF-8 window title").Str(),
dwStyle, x, y, width, height, parent, menu, hInstance, lpParam);
Regla de oro: use el formulario Unicode de la plataforma nativa para el procesamiento (UTF-16 o UTF-32), y UTF-8 para el intercambio de datos (comunicación, almacenamiento).
Si todas las API nativas usan UTF-16 (por ejemplo, en Windows), tener sus cadenas como UTF-8 significa que tendrá que convertir todas las entradas a UTF-16, llame a la API de Win y luego convierta la respuesta a UTF-8. Todo un dolor.
Pero si el problema principal es la interfaz de usuario, las cadenas son el problema simple. El más difícil es el marco de la interfaz de usuario. Y para eso recomendaría wxWidgets ( http://www.wxWidgets.org ). Soporta muchas plataformas, madura (17 años y todavía muy activa), widgets nativos, Unicode, licencia liberal.