python - programacion - ¿Por qué los lenguajes de script no envían Unicode a la consola de Windows?
manual de python 3.6 en español pdf (9)
¿Por qué demonios después de todos estos años no solo llaman a las API Win32 -W que generan Unicode UTF-16 en lugar de forzar todo a través del cuello de botella ANSI / página de códigos?
Porque Perl y Python no son programas de Windows. Son programas de Unix que se han portado principalmente a Windows. Como tal, no les gusta llamar a las funciones de Win32 a menos que sea necesario. Para la E / S basada en bytes, no es necesario; Esto se puede hacer con el estándar C Libary. La E / S basada en UTF-16 es un caso especial.
¿O son las API -W intrínsecamente rotas a tal grado que no pueden usarse como están?
No diría que las API -W están intrínsecamente dañadas tanto como diría que el enfoque de Microsoft para Unicode en C (++) está intrínsecamente dañado.
No importa cuánto ciertos desarrolladores de Windows insisten en que los programas deberían usar wchar_t
lugar de char
, hay demasiados obstáculos para cambiar:
- Dependencia de la plataforma:
- El uso de UTF-16
wchar_t
en Windows y UTF-32wchar_t
otros lugares. (Los nuevos tiposchar16_t
ychar32_t
pueden ayudar.) - La falta de estandarización de las funciones de nombre de archivo UTF-16 como
_wfopen
,_wstat
, etc. limita la capacidad de usarwchar_t
en el código multiplataforma.
- El uso de UTF-16
- Educación. Everbody aprende C con
printf("Hello, world!/n");
, nowprintf(L"Hello, world!/n");
. El libro de texto de C que usé en la universidad nunca mencionó caracteres anchos hasta el Apéndice A.13. - Los miles de millones de líneas de código existentes que utilizan cadenas de caracteres
char*
.
La consola de Windows ha sido consciente de Unicode durante al menos una década y tal vez se remonta a Windows NT. Sin embargo, por alguna razón, los principales lenguajes de scripts multiplataforma, incluidos Perl y Python, solo emiten varias codificaciones de 8 bits, lo que requiere muchos problemas para solucionarlos. Perl emite una advertencia de "caracteres anchos impresos", Python emite un error de mapa de encanto y se cierra. ¿Por qué demonios después de todos estos años no solo llaman a las API Win32 -W que generan Unicode UTF-16 en lugar de forzar todo a través del cuello de botella ANSI / página de códigos?
¿Es solo que el rendimiento multiplataforma es de baja prioridad? ¿Es que los lenguajes usan UTF-8 internamente y les resulta demasiado molesto producir UTF-16? ¿O son las API -W intrínsecamente rotas a tal grado que no pueden usarse como están?
ACTUALIZAR
Parece que la culpa puede ser compartida por todas las partes. Me imaginé que los lenguajes de scripting podrían simplemente llamar a wprintf
en Windows y dejar que el sistema operativo / tiempo de ejecución se preocupe por cosas como la redirección. ¡Pero resulta que incluso wprintf en Windows convierte caracteres anchos a ANSI y vuelve antes de imprimir en la consola !
Por favor, avíseme si esto se ha solucionado, ya que el enlace del informe de error parece estar roto pero mi código de prueba de Visual C todavía falla para wprintf y tiene éxito para WriteConsoleW.
ACTUALIZACIÓN 2
En realidad, puede imprimir UTF-16 en la consola desde C usando wprintf
pero solo si primero hace _setmode(_fileno(stdout), _O_U16TEXT)
.
Desde C, puede imprimir UTF-8 en una consola cuya página de códigos está configurada en la página de códigos 65001, sin embargo, Perl, Python, PHP y Ruby tienen errores que lo impiden. Perl y PHP dañan la salida al agregar líneas en blanco adicionales a las líneas que contienen al menos un carácter ancho. Ruby tiene una salida corrupta ligeramente diferente. Python se estrella.
ACTUALIZACIÓN 3
Node.js es el primer lenguaje de secuencias de comandos que se envió sin este problema desde el primer momento.
El equipo de desarrollo de Python se dio cuenta lentamente de que esto era un problema real, ya que se informó por primera vez a finales de 2007 y ha visto una gran actividad para comprender completamente y corregir el error en 2016.
¿Está seguro de que su script generaría Unicode en alguna otra plataforma correctamente? La advertencia de "carácter ancho en letra impresa" me hace muy sospechoso.
Recomiendo revisar este overview
El problema principal parece ser que no es posible usar Unicode en Windows usando solo la biblioteca estándar de C y sin extensiones de la plataforma o de terceros. Los idiomas que mencionó se originaron en las plataformas Unix, cuyo método de implementación de Unicode se combina bien con C (usan cadenas de caracteres normales char*
, las funciones de configuración regional de C y UTF-8). Si desea hacer Unicode en C, más o menos tiene que escribir todo dos veces: una vez que use extensiones de Microsoft no estándar y una vez que use las funciones estándar de la API de C para todos los demás sistemas operativos. Si bien esto se puede hacer, generalmente no tiene alta prioridad porque es incómodo y la mayoría de los desarrolladores de lenguaje de scripting odian o ignoran a Windows de todos modos.
En un nivel más técnico, creo que la suposición básica que hacen la mayoría de los diseñadores de bibliotecas estándar es que todas las transmisiones de E / S están inherentemente basadas en bytes en el nivel del sistema operativo, lo cual es cierto para los archivos en todos los sistemas operativos y para todas las transmisiones en Unix -como sistemas, con la consola de Windows como la única excepción. Por lo tanto, la arquitectura de muchas bibliotecas de clases y el lenguaje de programación estándar deben modificarse en gran medida si se desea incorporar la E / S de la consola de Windows.
Otro punto más subjetivo es que Microsoft simplemente no hizo lo suficiente para promover el uso de Unicode. El primer sistema operativo de Windows con soporte decente (para su época) de Unicode fue Windows NT 3.1, lanzado en 1993, mucho antes de que Linux y OS X crecieran en soporte de Unicode. Aún así, la transición a Unicode en esos sistemas operativos ha sido mucho más fluida y sin problemas. Microsoft una vez más escuchó a los vendedores en lugar de a los ingenieros, y mantuvo el Windows 9x técnicamente obsoleto hasta el 2001; en lugar de forzar a los desarrolladores a usar una interfaz limpia de Unicode, siguen enviando la interfaz API de 8 bits rota y ahora innecesaria, e invitan a los programadores a usarla (consulte algunas de las preguntas recientes de API de Windows sobre el Desbordamiento de pila, la mayoría de los novatos todavía usa la horrible API heredada!).
Cuando salió Unicode, muchas personas se dieron cuenta de que era útil. Unicode comenzó como una codificación de 16 bits pura, por lo que era natural utilizar unidades de código de 16 bits. Microsoft aparentemente dijo "OK, tenemos esta codificación de 16 bits, así que tenemos que crear una API de 16 bits", sin darnos cuenta de que nadie la usaría. Sin embargo, las luminarias de Unix pensaron "¿cómo podemos integrar esto en el sistema actual de una manera eficiente y compatible con versiones anteriores para que la gente realmente lo use?" e inventó posteriormente el UTF-8, que es una brillante pieza de ingeniería. Al igual que cuando se creó Unix, la gente de Unix pensó un poco más, necesitó un poco más, tuvo menos éxito financiero, pero finalmente lo hizo bien.
No puedo comentar sobre Perl (pero creo que hay más enemigos de Windows en la comunidad de Perl que en la comunidad de Python), pero con respecto a Python, sé que el BDFL (a quien no le gusta Windows también) ha declarado que el soporte adecuado de Unicode En todas las plataformas es un objetivo importante.
Michael Kaplan tiene una serie de publicaciones en el blog sobre la consola cmd
y Unicode que pueden ser informativas (aunque en realidad no responden a tu pregunta):
La sabiduría convencional es retardada, también conocida como ¿Qué @ #% & * es _O_U16TEXT?
Cualquiera que diga que la consola no puede hacer Unicode no es tan inteligente como ellos creen
Una confluencia de circunstancias deja una piedra sin remover ...
PD: Gracias @Jeff por encontrar los enlaces de archive.org.
Para Python, el problema relevante en el rastreador es http://bugs.python.org/issue1602 (como se dice en los comentarios). Tenga en cuenta que está abierto durante 7 años. Intenté publicar una solución de trabajo (basada en la información del problema) como un paquete de Python: https://github.com/Drekin/win-unicode-console , https://pypi.python.org/pypi/win_unicode_console .
Para que Perl sea totalmente compatible con Windows de esta manera, todas las llamadas para print
y warn
y die
deben modificarse.
- ¿Esto es Windows?
- ¿Qué versión de Windows? Perl todavía funciona principalmente en Windows 95
- ¿Esto va a la consola, o en algún otro lugar.
Una vez que haya determinado eso, entonces tendrá que usar un conjunto completamente diferente de funciones API.
Si realmente desea ver todo lo que implica hacer esto correctamente, eche un vistazo a la source de Win32 :: Unicode :: Console .
En Linux, OpenBSD, FreeBSD y sistemas operativos similares, generalmente puede llamar a binmode
en los STDERR
archivos STDOUT
y STDERR
.
binmode STDOUT, '':utf8'';
binmode STDERR, '':utf8'';
Esto supone que el terminal está utilizando la codificación UTF-8.
Pequeña contribución a la discusión: estoy ejecutando Windows XP localizado en checo, que en casi todas partes utiliza la página de códigos CP1250. Lo gracioso con la consola es que todavía usa la página de códigos DOS 852 heredada.
Pude hacer un script perl muy simple que imprime datos codificados en utf8 para la consola usando:
binmode STDOUT, ":utf8:encoding(cp852)";
Probé varias opciones (incluyendo utf16le), pero solo las configuraciones anteriores imprimieron correctamente los caracteres checos acentuados.
Edición: jugué un poco más con el problema y encontré Win32 :: Unicode . El módulo exporta la función printW
que funciona correctamente tanto en la salida como en el redireccionado:
use utf8;
use Win32::Unicode;
binmode STDOUT, ":utf8";
printW "Příliš žluťoučký kůň úpěl ďábelské ódy";
Tengo que responder muchas de tus preguntas.
Sabía usted que
- Windows usa UTF-16 para sus API, pero sigue siendo el valor predeterminado de las diversas codificaciones heredadas "divertidas" (p. Ej., Windows-1252, Windows-1251) en el espacio de usuario, incluidos los nombres de archivos, de forma diferente para las muchas localizaciones de Windows.
- necesita codificar la salida, y elegir la codificación apropiada para el sistema se logra con el pragma de configuración regional , y existe un estándar POSIX llamado locale en el que se construye, y Windows no es compatible con él?
- ¿Perl ya soportó las llamadas API "anchas" una vez?
- ¿Microsoft logró adaptar UTF-8 en su sistema de codificación de caracteres de la página de códigos, y puede cambiar su terminal emitiendo el comando
chcp 65001
apropiado?
explica cómo funciona la consola Win32 con Perl y la transcodificación que ocurre detrás de la escena de ANSI a Unicode, aunque no solo es un problema de Perl, sino que afecta a otros idiomas