2008-11-11 33 views
5

Cómo convertir cadena Unicode en una cadena utf-8 o utf-16? Mi proyecto VS2005 está utilizando juego de caracteres Unicode, mientras que en sqlite CPP proporcionarCómo convertir cadena Unicode en una cadena utf-8 o utf-16?

int sqlite3_open(
    const char *filename, /* Database filename (UTF-8) */ 
    sqlite3 **ppDb   /* OUT: SQLite db handle */ 
); 
int sqlite3_open16(
    const void *filename, /* Database filename (UTF-16) */ 
    sqlite3 **ppDb   /* OUT: SQLite db handle */ 
); 

para la apertura de una carpeta. ¿Cómo puedo convertir string, CString o wstring en UTF-8 o UTF-16 charset?

Muchas gracias!

Respuesta

6

Respuesta corta:

sin necesidad de conversión si utiliza cadenas Unicode como CString o wstring. Use sqlite3_open16(). Tendrás que asegurarte de pasar un puntero WCHAR (casted a void *. Parece cojo! Incluso si esta lib es multiplataforma, supongo que podrían haber definido un tipo de caracteres amplio que depende de la plataforma y es menos desagradable que un void *) a la API. Por ejemplo para un CString: (void*)(LPCWSTR)strFilename

La respuesta larga:

Usted no tiene una cadena Unicode que desea convertir a UTF8 o UTF16. Usted tiene una cadena Unicode representada en su programa usando una codificación dada: Unicode no es una representación binaria per se. Las codificaciones dicen cómo los puntos de código Unicode (valores numéricos) se representan en la memoria (diseño binario del número). UTF8 y UTF16 son las codificaciones más utilizadas. Sin embargo, son muy diferentes.

Cuando un proyecto VS dice "Juego de caracteres Unicode", en realidad significa "caracteres codificados como UTF16". Por lo tanto, puede usar sqlite3_open16() directamente. No se requiere conversión Los caracteres se almacenan en tipo WCHAR (a diferencia de char) que toma 16 bits (Retroceso en el estándar C tipo wchar_t, que toma 16 bits en Win32. Puede ser diferente en otras plataformas. Gracias por la corrección, Checkers).

Hay un detalle más que puede que desee prestar atención: UTF16 existe en 2 sabores: Big Endian y Little Endian. Ese es el orden de bytes de estos 16 bits. El prototipo de función que proporcione para UTF16 no indica qué orden se utiliza. Pero estás bastante seguro asumiendo que sqlite usa el mismo endian-ness que Windows (Little Endian IIRC. Conozco el orden, pero siempre he tenido problemas con los nombres :-)).

EDIT: respuesta al comentario de Damas:

UTF16 utiliza 16 bits unidades de código. En Win32 (y solo en Win32), wchar_t se utiliza para dicha unidad de almacenamiento. El truco es que algunos caracteres Unicode requieren una secuencia de 2 de esas unidades de código de 16 bits. Se llaman Pares de Sustituto.

De la misma forma que un UTF8 representa 1 carácter con una secuencia de 1 a 4 bytes. Sin embargo, UTF8 se usa con el tipo char.

+3

¡No, no, no! sqlite3_open16() usa el argumento 'void *', porque se dice que es UTF16, * NOT * wchar_t, que es de diferente tamaño en diferentes plataformas y puede o no ser UTF16 (es decir, glibc tiene 4-byte wchar_t). –

+0

Damas: vea mi respuesta como EDITAR aquí arriba –

+1

Sí, conozco la representación UTF16. Sin embargo, no puede suponer que la representación interna de wchar_t sea la misma en todas las plataformas, no lo es. –

7

Utilice la función WideCharToMultiByte. Especifique CP_UTF8 para el parámetro CodePage.

CHAR buf[256]; // or whatever 
WideCharToMultiByte(
    CP_UTF8, 
    0, 
    StringToConvert, // the string you have 
    -1, // length of the string - set -1 to indicate it is null terminated 
    buf, // output 
    __countof(buf), // size of the buffer in bytes - if you leave it zero the return value is the length required for the output buffer 
    NULL,  
    NULL 
); 

Además, la codificación predeterminada para las aplicaciones Unicode en las ventanas es UTF-16LE, por lo que es posible que no tenga que realizar ninguna traducción y sólo tiene que utilizar la segunda versión sqlite3_open16.

+0

No recomendaría un búfer fijo; en su lugar, utilice un búfer asignado dinámicamente (por ejemplo, std :: vector), expandiéndolo según sea necesario (cuando WideCharToMultiByte le dice que su cadena es demasiado pequeña). –

+1

Tengo que estar en desacuerdo: muestras cómo convertir de UTF16 a UTF8. Este no es el requisito del OP ya que parece haber una función disponible para cadenas de caracteres anchas: sqlite3_open16(). IMO, la respuesta correcta es: use sqlite3_open16(). –

+0

@Chris por eso dije "o lo que sea" y puse el comentario en el tamaño del búfer de salida - No quería complicar demasiado las cosas –

0

utf-8 y utf-16 son codificaciones de caracteres "unicode". De lo que probablemente hablas es de utf-32, que es una codificación de caracteres de tamaño fijo. Tal vez la búsqueda de

"Convert utf-32 into utf-8 or utf-16"

que proporciona unos resultados u otros documentos sobre esto.

3

Todos los tipos de cadenas C++ son neutros en el conjunto de caracteres. Simplemente se conforman con el ancho de un personaje y no hacen más suposiciones. Un wstring usa caracteres de 16 bits en Windows, que corresponden aproximadamente a utf-16, pero aún depende de lo que almacene en el hilo. El wstring de ninguna manera exige que los datos que ingrese sean válidos utf16. Sin embargo, Windows usa utf16 cuando se define UNICODE, por lo que es probable que sus cadenas ya sean utf16, y no es necesario que haga nada.

Algunos otros han sugerido utilizar la función WideCharToMultiByte, que es (uno de) los métodos para convertir utf16 a utf8. Pero como sqlite puede manejar utf16, eso no debería ser necesario.

0

La forma más sencilla de hacerlo es utilizar CStringA. La clase CString es un typedef para CStringA (versión ASCII) o CStringW (versión de char ancha). Ambas clases tienen constructores para convertir tipos de cadenas. Normalmente uso:

sqlite3_open(CStringA(L"MyWideCharFileName"), ...); 
Cuestiones relacionadas