Salida de cadenas Unicode en la aplicación de consola de Windows

13 minutos de lectura

Salida de cadenas Unicode en la aplicacion de consola de
Andrés

Hola, estaba tratando de enviar una cadena Unicode a una consola con iostreams y falló

Encontré esto: Usando la 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 ninguna otra solución que envolver este fragmento en una secuencia. 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; 
} 

  • ¿Podría aclarar exactamente cómo está fallando? ¿Estás consiguiendo caracteres ilegibles/incorrectos o algo así? ¿Ha intentado capturar STDOUT y verificar que se envían los bytes correctos pero tal vez no se muestran?

    – Goyuix

    30 de marzo de 2010 a las 20:13

  • Muestra marcadores de posición en lugar de caracteres. No me fijé mucho en ello. Lo único que puedo decir es que, por alguna razón, la misma cadena enviada a wcout o cout se vuelve loca mientras que wprintf la muestra sin problemas.

    – Andrés

    31 de marzo de 2010 a las 0:06

  • Solamente algunos Los caracteres Unicode se pueden mostrar correctamente dentro de la consola Win32. La consola no admite caracteres que sean demasiado complicados o que tengan marcas de combinación que afecten su tamaño. Pruébalo con WriteConsoleW — si no funciona con eso, entonces es imposible.

    – usuario541686

    29 de enero de 2012 a las 7:09


Salida de cadenas Unicode en la aplicacion de consola de
patomaestro

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

Solución:

#include <iostream>
#include <io.h>
#include <fcntl.h>

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 consola

  • +1 y eliminé mi respuesta. Este es el método que elegimos para Instalog.

    – Billy ONeal

    24 de abril de 2012 a las 2:01


  • todavía no muestra caracteres japoneses en mi consola.

    – sarat

    11 de abril de 2013 a las 9:39

  • +1 por la solución que funciona, pero uno debe tener en cuenta que esa es una solución específica de VIsual C ++: no necesariamente funcionará con g ++.

    – Saludos y hth. – alf

    19 de junio de 2014 a las 13:45

  • Doesn't work when you also have std::cout's De cplusplus.com: un programa no debe mezclar operaciones de salida en wcout con operaciones de salida en cout (o con otras operaciones de salida de orientación restringida en stdout): una vez que se ha realizado una operación de salida en cualquiera de los dos, el flujo de salida estándar adquiere una orientación ( ya sea estrecho o ancho) que solo se puede cambiar de forma segura llamando a freopen en stdout.

    –Roger Dahl

    26 de agosto de 2014 a las 17:01

  • @RogerDahl: No me esforcé mucho, pero parece (el documento de MS menciona en la Precaución) que podría retrasarse después de llamar a fflush(). Entonces, después de explícito _setmode()luego wcout << ..., hice ` wcout << flush; fflush(salida estándar); _setmode(_fileno(stdout), _O_TEXT);` y parece funcionar.

    – pimienta

    13 de enero de 2016 a las 11:38

1647579253 610 Salida de cadenas Unicode en la aplicacion de consola de
David

Hola mundo Unicode en chino

Aquí hay un Hola Mundo 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 desea una solución programática, en lugar de configurar la consola/registro, etc. Tal vez eche un vistazo aquí si realmente necesita hacer esto en Windows 7: Cambiar fuente de consola Windows 7

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

Esquema

  1. Configuración del proyecto Unicode
  2. Establecer la página de códigos de la consola en Unicode
  3. Encuentre y use una fuente que admita los caracteres que desea mostrar
  4. Use la configuración regional del idioma que desea mostrar
  5. Use la salida de caracteres anchos, es decir 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 experimenta problemas o usa un ide diferente, es posible que desee verificar estos:

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

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

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

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

  1. Página de códigos de la 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 sin 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 tanto la página de códigos de entrada como la de salida. Cuando omití cualquiera de los dos, el resultado fue incorrecto.

SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);

También es posible que desee verificar los valores de retorno booleanos de esas funciones.

  1. Elija una fuente ================

Hasta ahora no encontré una fuente de consola que admita todos los caracteres. Así que tuve que elegir uno. Si desea generar caracteres que en parte solo están disponibles en una fuente y en parte en otra fuente, 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 fuentes 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 parte superior izquierda de la ventana. Vaya a la pestaña de fuentes, elija una fuente y haga clic en Aceptar. Luego intente ingresar sus caracteres en la ventana de la consola. Repite esto hasta que encuentres una fuente con la que puedas trabajar. Luego 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 con el que está satisfecho, 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 configurar la fuente mediante programación, usa:

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

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

  1. Establecer la configuración regional =================

Deberá establecer la configuración regional en la configuración regional del idioma cuyos caracteres desea imprimir.

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

El valor de retorno es interesante. Contendrá una cadena para describir exactamente qué configuración regional se eligió. Pruébalo 🙂 Probé con chinese y german. Más información: establecerlocale

  1. Usar salida de caracteres anchos ============================

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

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

Ah, y no olvides el L prefijo para caracteres anchos! Y si escribe caracteres Unicode literales como este en el archivo de origen, el archivo de origen debe estar codificado en Unicode. Como el valor predeterminado en Visual Studio es UTF-16-LE. O tal vez usar bloc de notas++ y establezca la codificación en UCS-2 LE BOM.

Ejemplo

Finalmente lo puse todo junto como ejemplo:

#include <Windows.h>
#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <locale.h>
#include <wincon.h>

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 !

Editar el 2021-11-20

Tal vez también pueda intentar usar la nueva Terminal de Windows. Parece imprimir Unicode fuera de la caja. Aún necesitará configurar una fuente que admita sus caracteres en la configuración. Está desarrollado por Microsoft como OpenSource en github y también puedes instalarlo desde Microsoft Store. Intenté esto con éxito en Windows 10.

  • Esto no funciona para mí. Usando C con “wprintf(L”你好”);”

    – zezba9000

    31 de marzo de 2019 a las 4:08

  • Se cambió std::copy a “memcpy(fontInfo.FaceName, myFont, (sizeof(myFont)));” y funciona bien en C++ con un archivo .cpp pero no si compilo para C con un archivo .c.

    – zezba9000

    31 de marzo de 2019 a las 4:21

  • Nvr mente, está funcionando. Solo tiene que asegurarse de que su archivo fuente tenga la codificación UTF-8 correcta (con firma).

    – zezba9000

    31 de marzo de 2019 a las 4:32

  • SetCurrentConsoleFontEx La función está en modo de soporte y ya no se recomienda su uso en nuevas aplicaciones de línea de comandos.

    – Luan Vítor

    27/09/2021 a las 17:49

1647579253 297 Salida de cadenas Unicode en la aplicacion de consola de
vitalidad

Puedes usar la biblioteca de código abierto {fmt} para imprimir texto Unicode de forma portátil, incluso en Windows, por ejemplo:

#include <fmt/core.h>

int main() {
  fmt::print("èéøÞǽлљΣæča");
}

Producción:

èéøÞǽлљΣæča

Esto requiere compilar con el /utf-8 opción del compilador en MSVC.

no recomiendo usar wcout porque no es portátil y ni siquiera funciona en Windows sin esfuerzos adicionales, por ejemplo:

std::wcout << L"èéøÞǽлљΣæča";

imprimirá:

├и├й├╕├Ю╟╜╨╗╤Щ╬г├ж─Нa

en ruso Windows (ACP 1251, consola CP 866).

Descargo de responsabilidad: Soy el autor de {fmt}.

El wcout debe tener la configuración regional diferente a la del 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;
}

Lo acabo de probar y muestra la cadena aquí absolutamente bien.

SetConsoleCP() y CHCP no da lo mismo!

Tome este fragmento de programa:

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 compilador de Microsoft cl.exe toma las cadenas UTF-8 tal cual.
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 la pantalla a Consola Lucidiade lo contrario, la salida UTF-8 no funcionará en absoluto.

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

Probado con: Windows XP SP3 alemán

  • puedes usar constantes de caracteres como \x45 para hacer que la cadena funcione independientemente de la codificación de origen

    – phuclv

    6 de junio de 2014 a las 3:06

  • -1 mal consejo para engañar al compilador, lo que resulta en una compilación incorrecta de literales amplios.

    – Saludos y hth. – alf

    19 de junio de 2014 a las 13:41

  • Realmente desea usar escapes para no depender de cómo el editor guarda los caracteres que no son ASCII en la fuente y los interpreta el compilador. Por ejemplo, la cadena UTF-8 de la respuesta se puede escribir de forma portátil como "tr\xc3\xa4nen\xc3\xbcberstr\xc3\xb6mt\xe2\x84\xa2".

    – usuario4815162342

    16 de noviembre de 2014 a las 11:46


  • SetConsoleCP solo afecta la entrada, por lo que no sorprende en absoluto que no funcione en su ejemplo. Está SetConsoleOutputCP que controla la codificación de salida.

    – rdb

    22 de noviembre de 2017 a las 14:12

1647579254 705 Salida de cadenas Unicode en la aplicacion de consola de
llámame Steve

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

  • puedes usar constantes de caracteres como \x45 para hacer que la cadena funcione independientemente de la codificación de origen

    – phuclv

    6 de junio de 2014 a las 3:06

  • -1 mal consejo para engañar al compilador, lo que resulta en una compilación incorrecta de literales amplios.

    – Saludos y hth. – alf

    19 de junio de 2014 a las 13:41

  • Realmente desea usar escapes para no depender de cómo el editor guarda los caracteres que no son ASCII en la fuente y los interpreta el compilador. Por ejemplo, la cadena UTF-8 de la respuesta se puede escribir de forma portátil como "tr\xc3\xa4nen\xc3\xbcberstr\xc3\xb6mt\xe2\x84\xa2".

    – usuario4815162342

    16 de noviembre de 2014 a las 11:46


  • SetConsoleCP solo afecta la entrada, por lo que no sorprende en absoluto que no funcione en su ejemplo. Está SetConsoleOutputCP que controla la codificación de salida.

    – rdb

    22 de noviembre de 2017 a las 14:12

Recientemente, quería transmitir Unicode desde Python a la consola de Windows y esto es lo mínimo que necesitaba hacer:

  • Debe establecer la fuente de la consola en la que cubre los símbolos Unicode. No hay muchas opciones: Propiedades de la consola > Fuente > Consola Lucida
  • Debe cambiar la página de códigos de la consola actual: ejecutar chcp 65001 en la Consola o use el método correspondiente en el código C++
  • escribir en la consola usando WriteConsoleW

Mira un artículo interesante sobre java unicode en la consola de windows

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

  • Debe configurar la fuente, esta parte es correcta y es un diseño deficiente de Windows que no utiliza de manera predeterminada una fuente que funcione para un rango decente de caracteres Unicode. Sin embargo, la siguiente parte de su respuesta es incorrecta. NO necesita establecer la página de códigos en UTF-8/65001 Y llamar a WriteConsoleW. Tienes que hacer uno o el otro. Establezca la página de códigos si llamará a WriteConsoleA y pasará cadenas de 8 bits, incluido UTF-8, PERO simplemente llamar a WriteConsoleW omite completamente las páginas de códigos y requiere UTF-16 (caracteres anchos). Sin embargo, en mi experiencia, configurar la consola en 65001 es bastante defectuoso.

    – pista hippie

    17 de febrero de 2011 a las 6:48

  • @hippietrail: no estoy seguro de escribir con WriteConsoleW sin cambiar la página de códigos a 65001, pero configurar solo 65001 lamentablemente no es suficiente. Al menos para la salida Unicode de los scripts de Python.

    – newtover

    24 de marzo de 2011 a las 19:44

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad