Cadenas de salida de unicode en la aplicación de consola de Windows

Hola. Estaba intentando sacar una cadena Unicode a una consola con iostreams y fallé.

Encontré esto: Usar fuente unicode en la aplicación de consola c ++ y este fragmento funciona.

SetConsoleOutputCP(CP_UTF8); wchar_t s[] = L"èéøÞǽлљΣæča"; int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char* m = new char[bufferSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL); wprintf(L"%S", m); 

Sin embargo, no encontré ninguna forma de generar unicode correctamente con iostreams. ¿Alguna sugerencia?

Esto no funciona:

 SetConsoleOutputCP(CP_UTF8); utf8_locale = locale(old_locale,new boost::program_options::detail::utf8_codecvt_facet()); wcout.imbue(utf8_locale); wcout << L"¡Hola!" << endl; 

EDITAR No pude encontrar otra solución que envolver este fragmento en una transmisión. Espero que alguien tenga mejores ideas.

 //Unicode output for a Windows console ostream &operator-(ostream &stream, const wchar_t *s) { int bufSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char *buf = new char[bufSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, buf, bufSize, NULL, NULL); wprintf(L"%S", buf); delete[] buf; return stream; } ostream &operator-(ostream &stream, const wstring &s) { stream - s.c_str(); return stream; } 

He verificado una solución aquí con Visual Studio 2010. A través de este artículo de MSDN y la publicación de blog de MSDN . El truco es una llamada oscura a _setmode(..., _O_U16TEXT) .

Solución:

 #include  #include  #include  int wmain(int argc, wchar_t* argv[]) { _setmode(_fileno(stdout), _O_U16TEXT); std::wcout << L"Testing unicode -- English -- Ελληνικά -- Español." << std::endl; } 

Captura de pantalla:

Unicode en la consola

El wcout debe tener la configuración regional configurada de forma diferente al CRT. Así es como se puede arreglar:

 int _tmain(int argc, _TCHAR* argv[]) { char* locale = setlocale(LC_ALL, "English"); // Get the CRT's current locale. std::locale lollocale(locale); setlocale(LC_ALL, locale); // Restore the CRT. std::wcout.imbue(lollocale); // Now set the std::wcout to have the locale that we got from the CRT. std::wcout << L"¡Hola!"; std::cin.get(); return 0; } 

Acabo de probarlo, y muestra la cadena aquí absolutamente bien.

SetConsoleCP () y chcp no es lo mismo!

Toma este fragmento de progtwig:

 SetConsoleCP(65001) // 65001 = UTF-8 static const char s[]="tränenüberströmt™\n"; DWORD slen=lstrlen(s); WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE),s,slen,&slen,NULL); 

El código fuente debe guardarse como UTF-8 sin BOM (Marca de orden de bytes, Firma). Luego, el comstackdor de Microsoft cl.exe toma las cadenas UTF-8 tal como están.
Si este código se guarda con BOM, cl.exe transcodifica la cadena a ANSI (es decir, CP1252), que no coincide con CP65001 (= UTF-8).

Cambie la fuente de visualización a Lucidia Console ; de lo contrario, la salida UTF-8 no funcionará en absoluto.

  • Tipo: chcp
  • Respuesta: 850
  • Tipo: test.exe
  • Respuesta: tr├ñnen├╝berstr├ÂmtÔäó
  • Tipo: chcp
  • Respuesta: 65001 – Esta configuración ha cambiado por SetConsoleCP() pero sin ningún efecto útil.
  • Tipo: chcp 65001
  • Tipo: test.exe
  • Respuesta: tränenüberströmt™ – Todo está bien ahora.

Probado con: alemán Windows XP SP3

Unicode Hello World en chino

Aquí hay un Hello World en chino. En realidad, es solo “Hola”. Probé esto en Windows 10, pero creo que podría funcionar desde Windows Vista. Antes de Windows Vista será difícil, si quieres una solución programática, en lugar de configurar la consola / registro, etc. Tal vez echar un vistazo aquí si realmente necesita hacer esto en Windows 7: cambiar la consola de la fuente de Windows 7

No quiero afirmar que esta es la única solución, pero esto es lo que funcionó para mí.

contorno

  1. Configuración del proyecto Unicode
  2. Establezca la página de códigos de la consola en Unicode
  3. Encuentre y use una fuente que admita los caracteres que desea visualizar
  4. Use la configuración regional del idioma que desea mostrar
  5. Utilice la salida de caracteres anchos, por ej. std::wcout

1 Configuración del proyecto

Estoy usando Visual Studio 2017 CE. Creé una aplicación de consola en blanco. La configuración predeterminada está bien. Pero si tiene problemas o usa una ide diferente, puede verificar esto:

En las propiedades de su proyecto, busque las propiedades de configuración -> General -> Valores predeterminados del proyecto -> Conjunto de caracteres. Debería ser “Usar conjunto de caracteres Unicode”, no “Multi-Byte”. Esto definirá las macros de preprocesador _UNICODE y UNICODE para usted.

 int wmain(int argc, wchar_t* argv[]) 

También creo que deberíamos usar la función wmain lugar de main . Ambos funcionan, pero en un entorno unicode, puede ser más conveniente.

Además, mis archivos de origen están codificados con UTF-16-LE, que parece ser el predeterminado en Visual Studio 2017.

2. Página de códigos de consola

Esto es bastante obvio. Necesitamos la página de códigos Unicode en la consola. Si desea verificar su página de códigos predeterminada, simplemente abra una consola y escriba chcp ningún argumento. Tenemos que cambiarlo a 65001, que es la página de códigos UTF-8. Identificadores de página de códigos de Windows Hay una macro de preprocesador para esa página de códigos: CP_UTF8 . Necesitaba configurar ambas, la página de códigos de entrada y salida. Cuando omití cualquiera de los dos, la salida fue incorrecta.

 SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); 

Es posible que también desee comprobar los valores de retorno booleanos de esas funciones.

3. Elija una fuente

Hasta ahora, no encontré una fuente de consola que sea compatible con todos los personajes. Entonces tuve que elegir uno. Si desea generar caracteres que en parte solo están disponibles en una fuente y en parte en otra fuente, entonces creo que es imposible encontrar una solución. Solo tal vez si hay una fuente que admita todos los caracteres. Pero tampoco investigué cómo instalar una fuente.

Creo que no es posible usar dos fonts diferentes en la misma ventana de la consola al mismo tiempo.

¿Cómo encontrar una fuente compatible? Abra su consola, vaya a las propiedades de la ventana de la consola haciendo clic en el icono en la esquina superior izquierda de la ventana. Vaya a la pestaña de fonts y elija una fuente y haga clic en Aceptar. Luego intenta ingresar tus personajes en la ventana de la consola. Repite esto hasta que encuentres una fuente con la que puedas trabajar. A continuación, anote el nombre de la fuente.

También puede cambiar el tamaño de la fuente en la ventana de propiedades. Si encontró un tamaño que le satisface, anote los valores de tamaño que se muestran en la ventana de propiedades en la sección “fuente seleccionada”. Mostrará ancho y alto en píxeles.

Para establecer realmente la fuente mediante progtwigción, utiliza:

 CONSOLE_FONT_INFOEX fontInfo; // ... configure fontInfo SetCurrentConsoleFontEx(hConsole, false, &fontInfo); 

Vea mi ejemplo al final de esta respuesta para más detalles. O búsquelo en el fino manual: SetCurrentConsoleFont . Esta función solo existe desde Windows Vista.

4. Configure la configuración regional

Tendrá que establecer la configuración regional en la configuración regional del idioma que desea imprimir.

 char* a = setlocale(LC_ALL, "chinese"); 

El valor de retorno es interesante. Contendrá una cadena para describir exactamente qué escenario se eligió. Solo pruébalo 🙂 Probé con chinese y german . Más información: setlocale

5. Utilice salida de caracteres anchos

No hay mucho que decir aquí. Si desea imprimir caracteres anchos, use esto por ejemplo:

 std::wcout << L"你好" << std::endl; 

¡Ah, y no olvides el prefijo L para los personajes anchos! Y si escribe caracteres literales Unicode como este en el archivo fuente, el archivo fuente debe ser codificado en unicode. Al igual que el valor predeterminado en Visual Studio es UTF-16-LE. O tal vez use notepad ++ y configure la encoding para UCS-2 LE BOM .

Ejemplo

Finalmente lo puse todo junto como un ejemplo:

 #include  #include  #include  #include  #include  #include  int wmain(int argc, wchar_t* argv[]) { SetConsoleTitle(L"My Console Window - 你好"); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); char* a = setlocale(LC_ALL, "chinese"); SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); CONSOLE_FONT_INFOEX fontInfo; fontInfo.cbSize = sizeof(fontInfo); fontInfo.FontFamily = 54; fontInfo.FontWeight = 400; fontInfo.nFont = 0; const wchar_t myFont[] = L"KaiTi"; fontInfo.dwFontSize = { 18, 41 }; std::copy(myFont, myFont + (sizeof(myFont) / sizeof(wchar_t)), fontInfo.FaceName); SetCurrentConsoleFontEx(hConsole, false, &fontInfo); std::wcout << L"Hello World!" << std::endl; std::wcout << L"你好!" << std::endl; return 0; } 

¡Salud!

No creo que haya una respuesta fácil. mirando las páginas de códigos de la consola y la función SetConsoleCP , parece que necesitará configurar una página de códigos apropiada para el conjunto de caracteres que va a generar.

Hace poco quise transmitir unicode desde Python a la consola de Windows y aquí está el mínimo que necesitaba hacer:

  • Debe configurar la fuente de la consola para que cubra los símbolos Unicode. No hay una gran elección: Propiedades de la consola> Fuente> Consola Lucida
  • Debe cambiar la página de códigos de la consola actual: ejecute chcp 65001 en la consola o use el método correspondiente en el código de C ++.
  • escribir en consola usando WriteConsoleW

Mire a través de un artículo interesante sobre Java Unicode en la consola de Windows

Además, en Python no puede escribir a sys.stdout por defecto en este caso, deberá sustituirlo por algo usando os.write (1, binarystring) o llamada directa a un contenedor alrededor de WriteConsoleW. Parece que en C ++ tendrás que hacer lo mismo.

Primero, lo siento, probablemente no tenga las fonts necesarias, así que aún no puedo probarlo.

Algo se ve un poco sospechoso aquí

 // the following is said to be working SetConsoleOutputCP(CP_UTF8); // output is in UTF8 wchar_t s[] = L"èéøÞǽлљΣæča"; int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char* m = new char[bufferSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL); wprintf(L"%S", m); // <-- upper case %S in wprintf() is used for MultiByte/utf-8 // lower case %s in wprintf() is used for WideChar printf("%s", m); // <-- does this work as well? try it to verify my assumption 

mientras

 // the following is said to have problem SetConsoleOutputCP(CP_UTF8); utf8_locale = locale(old_locale, new boost::program_options::detail::utf8_codecvt_facet()); wcout.imbue(utf8_locale); wcout << L"¡Hola!" << endl; // <-- you are passing wide char. // have you tried passing the multibyte equivalent by converting to utf8 first? int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char* m = new char[bufferSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL); cout << m << endl; 

qué pasa

 // without setting locale to UTF8, you pass WideChars wcout << L"¡Hola!" << endl; // set locale to UTF8 and use cout SetConsoleOutputCP(CP_UTF8); cout << utf8_encoded_by_converting_using_WideCharToMultiByte << endl; 

Hay algunos problemas con las transmisiones mswcrt e io.

  1. Trick _setmode (_fileno (stdout), _O_U16TEXT); trabajando solo para MS VC ++ no MinGW-GCC. Además, a veces se bloquea según la configuración de Windows.
  2. SetConsoleCP (65001) para UTF-8. Puede fallar en muchos escenarios de caracteres multibyte, pero siempre está bien para UTF-16LE
  3. Debe restaurar la página de códigos de la consola de previsualización al salir de la aplicación.

La consola de Windows admite UNICODE con las funciones ReadConsole y WriteConsole en el modo UTF-16LE. Efecto de fondo: la tubería en este caso no funcionará. Es decir, myapp.exe >> ret.log lleva al archivo ret.log de 0 bytes. Si estás de acuerdo con este hecho, puedes probar mi biblioteca de la siguiente manera.

 const char* umessage = "Hello!\nПривет!\nПривіт!\nΧαιρετίσματα!\nHelló!\nHallå!\n"; ... #include  #include  ... std::ostream& cout = io::console::out_stream(); cout << umessage << 1234567890ull << '\n' << 123456.78e+09 << '\n' << 12356.789e+10L << '\n' << std::hex << 0xCAFEBABE << std::endl; 

La Biblioteca convertirá automáticamente su UTF-8 en UTF-16LE y la escribirá en la consola usando WriteConsole. Además de errores y flujos de entrada. Otra ventaja de la biblioteca: colores.

Enlace en la aplicación de ejemplo: https://github.com/incoder1/IO/tree/master/examples/iostreams

La página principal de la biblioteca: https://github.com/incoder1/IO

Captura de pantalla:

Tuve un problema similar, Salida Unicode a consola Usando C ++, en Windows contiene la joya que necesita para hacer chcp 65001 en la consola antes de ejecutar su progtwig.

Puede haber alguna manera de hacerlo programáticamente, pero no sé qué es.

Mostrar correctamente los caracteres de Europa occidental en la consola de Windows

Larga historia corta:

  1. use chcp para encontrar qué página de códigos le funciona. En mi caso, fue chcp 28591 para Europa Occidental.
  2. opcionalmente, REG ADD HKCU\Console /v CodePage /t REG_DWORD /d 28591 predeterminada: REG ADD HKCU\Console /v CodePage /t REG_DWORD /d 28591

Historia del descubrimiento

Tuve un problema similar con Java. Es simplemente cosmético, ya que involucra líneas de registro enviadas a la consola; pero sigue siendo molesto

La salida de nuestra aplicación Java se supone que está en UTF-8 y se muestra correctamente en la consola de eclipse. Pero en la consola de Windows, solo muestra los caracteres de dibujo en cuadro ASCII: Inicializaci├│n y art├¡culos lugar de Inicialización y artículos .

Encontré una pregunta relacionada y mezclé algunas de las respuestas para llegar a la solución que funcionó para mí. La solución es cambiar la página de códigos utilizada por la consola y usar una fuente que admita UNICODE (como consolas o lucida console ). La fuente que puede seleccionar en el menú del sistema del coso de Windows:

  1. Inicie una consola por cualquiera de
    • Win + R luego escribe cmd y presiona la tecla Return .
    • Presiona la tecla Win y escribe cmd seguido de la tecla de return .
  2. Abra el menú del sistema por cualquiera de
    • haga clic en el ícono de la esquina superior izquierda
    • Presiona la combinación de teclas Alt + Space
  3. a continuación, seleccione “Predeterminado” para cambiar el comportamiento de todas las ventanas posteriores de la consola
  4. haga clic en la pestaña “Fuente”
  5. Seleccione la Lucida console Consolas o Lucida console
  6. Click OK

Con respecto a la página de códigos, para un caso chcp , puede hacerlo con el comando chcp y luego debe investigar qué página de códigos es la correcta para su conjunto de caracteres. Varias respuestas sugirieron la página de códigos UTF-8, que es 65001, pero esa página de códigos no funcionaba para mis caracteres en español.

Otra respuesta sugirió un script por lotes para seleccionar interactivamente la página de códigos que quería de una lista. Allí encontré la página de códigos ISO-8859-1 que necesitaba: 28591. Así que podrías ejecutar

 chcp 28591 

antes de cada ejecución de su aplicación. Puede verificar qué página de códigos es adecuada para usted en la página MSDN Identificadores de página de códigos .

Otra respuesta más indicó cómo persistir la página de códigos seleccionada como predeterminada para su consola de Windows. Implica cambiar el registro, así que considérese advertido de que puede bloquear su máquina utilizando esta solución.

 REG ADD HKCU\Console /v CodePage /t REG_DWORD /d 28591 

Esto crea el valor de CodePage con los datos 28591 dentro de la clave de registro HKCU \ Console. Y eso funcionó para mí.

Tenga en cuenta que HKCU (“HKEY_CURRENT_USER”) es solo para el usuario actual. Si desea cambiarlo para todos los usuarios de esa computadora, necesitará usar la utilidad regedit y buscar / crear la clave de Console correspondiente (probablemente tendrá que crear una clave de Console dentro de HKEY_USERS\.DEFAULT )