2012-04-04 9 views
5

Al usar printf para dar formato a una cadena de doble byte en una cadena de un solo byte:¿Por qué printf no formatea los parámetros unicode?

printf("%ls\n", L"s:\\яшертыHello"); // %ls for a wide string (%s varies meaning depending on the project's unicode settings). 

Claramente, algunos caracteres no pueden representarse como caracteres ASCII, el comportamiento así que a veces he visto que los caracteres de doble byte convertirse en un '?' marca el personaje Pero, esto parece depender de los personajes particulares. Para el printf anteriormente, la salida es:

s:\ 

Tenía la esperanza de que podría conseguir algo como:

s:\??????Hello 

Me temo que he perdido el ejemplo, pero creo que para una cadena cuando encontró caracteres unicode, reemplazó el primero con un '?' y luego desistió del resto.

Por lo tanto, mi pregunta es, ¿qué se supone que ocurre al formatear una cadena ancha en una cadena de un solo byte. Documentación aquí: http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx dice "Los caracteres se muestran hasta el primer carácter nulo". Pero, no estoy viendo eso. ¿Es esto un error en printf, o es el comportamiento que estoy viendo documentado en alguna parte? Si es así, dónde.

Gracias por su ayuda.

ACTUALIZACIÓN

Gracias por las respuestas de las personas que me dan alternativas al uso de printf. Voy a cambiar a una alternativa, pero estoy realmente interesado por curiosidad, ¿por qué printf no tiene un comportamiento documentado confiable? Parece como si el implementador de la misma hubiera salido de su camino para que esto no funcionara.

+2

¿Ha probado "% S" como el especificador de formato en lugar de "% ls"? –

+0

sí. Creo que% S y% ls tienen el mismo significado si su proyecto no tiene UNICODE definido. –

+1

Lectura de las especificaciones de formato (que acepto no son claras). S es para una cadena ancha cuando la configuración de su proyecto no tiene definido UNICODE, S es para una cadena de un solo byte cuando tiene definido UNICODE. % ls es para una cadena ancha independientemente de si está compilando o no para UNICODE o no. % s también varía el significado,% hs siempre es para cadenas de un solo byte. –

Respuesta

10

Espero que su código funcione, y funciona aquí en Linux, pero depende de la configuración regional. Eso significa que tiene que configurar la configuración regional y su configuración regional debe ser compatible con el conjunto de caracteres utilizado. Aquí está mi programa de pruebas:

#include <locale.h> 
#include <stdio.h> 

int main() 
{ 
    int c; 
    char* l = setlocale(LC_ALL, ""); 
    if (l == NULL) { 
     printf("Locale not set\n"); 
    } else { 
     printf("Locale set to %s\n", l); 
    } 
    printf("%ls\n", L"s:\\яшертыHello"); 
    return 0; 
} 

y Aquí se presenta una traza de ejecución:

$ env LC_ALL=en_US.utf8 ./a.out 
Locale set to en_US.utf8 
s:\яшертыHello 

Si dice que la configuración regional no se establece o se establece en "C", es normal que se no obtengas el resultado que esperas

Editar: vea las respuestas a this question por el equivalente de en_US.utf8 para Windows.

+0

Hmm. Esta respuesta parece estar en el tipo correcto de área. Me pregunto cómo has configurado tu configuración regional en utf8, aunque ... cuando intento eso, setlocale falla. Los documentos aquí: http://msdn.microsoft.com/en-us/library/x99tb11d.aspx (si busca utf-8) dice que fallará si prueba utf-8. Tal vez simplemente no funciona en la implementación de Microsoft. –

+0

@ScottLangham, los nombres de la configuración regional no están estandarizados y no sé qué es compatible con Windows, pero me sorprendería que no tengan ningún entorno Unicode, no necesariamente UTF8. – AProgrammer

+1

Windows no admite una configuración regional 'Unicode'. En todas las implementaciones, la codificación de wchar_t es independiente de la configuración regional, por lo que la codificación de una localidad solo se relaciona con la codificación de caracteres estrecha. Por lo tanto, una configuración regional 'Unicode' requiere esencialmente UTF-8, y Windows no proporciona ninguna configuración regional utilizando UTF-8. Windows admite Unicode utilizando UTF-16 como la codificación wchar_t. – bames53

5

En C++ utilizo generalmente std::stringstream para crear texto formateado. También he implementado un operador propia para utilizar la función de Windows para realizar la codificación:

ostream & operator << (ostream &os, const wchar_t * str) 
{ 
    if ((str == 0) || (str[0] == L'\0')) 
    return os; 
    int new_size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, NULL, NULL, NULL); 
    if (new_size <= 0) 
    return os; 
    std::vector<char> buffer(new_size); 
    if (WideCharToMultiByte(CP_UTF8, 0, str, -1, &buffer[0], new_size, NULL, NULL) > 0) 
    os << &buffer[0]; 
    return os; 
} 

Este código convertir a UTF-8. Para otras posibilidades, verifique: WideCharToMultiByte.

+0

Buen ejemplo de cómo hacerlo :) – jcoder

+0

@JohnB: ¡gracias! :) – Naszta

Cuestiones relacionadas