programa - Cómo imprimir una cadena Unicode en Python en la consola de Windows
ejecutar script python en windows (5)
¿Puedes intentar usar el iconv
del programa en Windows y conectar tu salida de Python a través de él? Sería algo como esto:
python foo.py | iconv -f utf-8 -t utf-16
Es posible que tenga que trabajar un poco para obtener iconv
en Windows: es parte de Cygwin, pero es posible que pueda compilarlo por separado de alguna manera si es necesario.
Esta pregunta ya tiene una respuesta aquí:
- Python, Unicode y la consola de Windows 11 respuestas
Estoy trabajando en una aplicación de Python que puede imprimir texto en múltiples idiomas a la consola en múltiples plataformas. El programa funciona bien en todas las plataformas UNIX, pero en Windows hay errores al imprimir cadenas unicode en línea de comandos.
Ya hay un hilo relevante sobre esto: (El cambio de codificación de cmd de Windows causa el bloqueo de Python ) pero no pude encontrar mi respuesta específica ahí.
Por ejemplo, para el siguiente texto asiático, en Linux, puedo ejecutar:
>>> print u"/u5f15/u8d77/u7684/u6216".encode("utf-8")
引起的或
Pero en Windows obtengo:
>>> print u"/u5f15/u8d77/u7684/u6216".encode("utf-8")
σ╝ץΦ╡╖τתהµטצ
Logré mostrar el texto correcto con un cuadro de mensaje cuando hacía algo como eso:
>>> file("bla.vbs", "w").write(u''MsgBox "/u5f15/u8d77/u7684/u6216", 4, "MyTitle"''.encode("utf-16"))
>>> os.system("cscript //U //NoLogo bla.vbs")
Pero, quiero poder hacerlo en la consola de Windows, y preferiblemente, sin requerir demasiada configuración fuera de mi código python (porque mi aplicación se distribuirá a muchos hosts).
es posible?
Editar: si no es posible, me complacería aceptar algunas otras sugerencias de escribir una aplicación de consola en Windows que muestre unicode, por ejemplo, una implementación de Python de una consola de Windows alternativa
Hay una solución WriteConsoleW que proporciona un unicode argv y stdout (print) pero no stdin: el cambio de codificación de cmd de Windows causa la falla de Python
Lo único que modifiqué es sys.argv para mantenerlo unicode. La versión original utf-8 lo codificó por alguna razón.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" https://.com/questions/878972/windows-cmd-encoding-change-causes-python-crash#answer-3259271
"""
import sys
if sys.platform == "win32":
import codecs
from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int
from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR, LPVOID
original_stderr = sys.stderr
# If any exception occurs in this code, we''ll probably try to print it on stderr,
# which makes for frustrating debugging if stderr is directed to our wrapper.
# So be paranoid about catching errors and reporting them to original_stderr,
# so that we can at least see them.
def _complain(message):
print >>original_stderr, message if isinstance(message, str) else repr(message)
# Work around <http://bugs.python.org/issue6058>.
codecs.register(lambda name: codecs.lookup(''utf-8'') if name == ''cp65001'' else None)
# Make Unicode console output work independently of the current code page.
# This also fixes <http://bugs.python.org/issue1602>.
# Credit to Michael Kaplan <http://www.siao2.com/2010/04/07/9989346.aspx>
# and TZOmegaTZIOY
# <https://.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462>.
try:
# <http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
# HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
# returns INVALID_HANDLE_VALUE, NULL, or a valid handle
#
# <http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
# DWORD WINAPI GetFileType(DWORD hFile);
#
# <http://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
# BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32))
STD_OUTPUT_HANDLE = DWORD(-11)
STD_ERROR_HANDLE = DWORD(-12)
GetFileType = WINFUNCTYPE(DWORD, DWORD)(("GetFileType", windll.kernel32))
FILE_TYPE_CHAR = 0x0002
FILE_TYPE_REMOTE = 0x8000
GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(("GetConsoleMode", windll.kernel32))
INVALID_HANDLE_VALUE = DWORD(-1).value
def not_a_console(handle):
if handle == INVALID_HANDLE_VALUE or handle is None:
return True
return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
or GetConsoleMode(handle, byref(DWORD())) == 0)
old_stdout_fileno = None
old_stderr_fileno = None
if hasattr(sys.stdout, ''fileno''):
old_stdout_fileno = sys.stdout.fileno()
if hasattr(sys.stderr, ''fileno''):
old_stderr_fileno = sys.stderr.fileno()
STDOUT_FILENO = 1
STDERR_FILENO = 2
real_stdout = (old_stdout_fileno == STDOUT_FILENO)
real_stderr = (old_stderr_fileno == STDERR_FILENO)
if real_stdout:
hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
if not_a_console(hStdout):
real_stdout = False
if real_stderr:
hStderr = GetStdHandle(STD_ERROR_HANDLE)
if not_a_console(hStderr):
real_stderr = False
if real_stdout or real_stderr:
# BOOL WINAPI WriteConsoleW(HANDLE hOutput, LPWSTR lpBuffer, DWORD nChars,
# LPDWORD lpCharsWritten, LPVOID lpReserved);
WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), LPVOID)(("WriteConsoleW", windll.kernel32))
class UnicodeOutput:
def __init__(self, hConsole, stream, fileno, name):
self._hConsole = hConsole
self._stream = stream
self._fileno = fileno
self.closed = False
self.softspace = False
self.mode = ''w''
self.encoding = ''utf-8''
self.name = name
self.flush()
def isatty(self):
return False
def close(self):
# don''t really close the handle, that would only cause problems
self.closed = True
def fileno(self):
return self._fileno
def flush(self):
if self._hConsole is None:
try:
self._stream.flush()
except Exception as e:
_complain("%s.flush: %r from %r" % (self.name, e, self._stream))
raise
def write(self, text):
try:
if self._hConsole is None:
if isinstance(text, unicode):
text = text.encode(''utf-8'')
self._stream.write(text)
else:
if not isinstance(text, unicode):
text = str(text).decode(''utf-8'')
remaining = len(text)
while remaining:
n = DWORD(0)
# There is a shorter-than-documented limitation on the
# length of the string passed to WriteConsoleW (see
# <http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
retval = WriteConsoleW(self._hConsole, text, min(remaining, 10000), byref(n), None)
if retval == 0 or n.value == 0:
raise IOError("WriteConsoleW returned %r, n.value = %r" % (retval, n.value))
remaining -= n.value
if not remaining:
break
text = text[n.value:]
except Exception as e:
_complain("%s.write: %r" % (self.name, e))
raise
def writelines(self, lines):
try:
for line in lines:
self.write(line)
except Exception as e:
_complain("%s.writelines: %r" % (self.name, e))
raise
if real_stdout:
sys.stdout = UnicodeOutput(hStdout, None, STDOUT_FILENO, ''<Unicode console stdout>'')
else:
sys.stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno, ''<Unicode redirected stdout>'')
if real_stderr:
sys.stderr = UnicodeOutput(hStderr, None, STDERR_FILENO, ''<Unicode console stderr>'')
else:
sys.stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno, ''<Unicode redirected stderr>'')
except Exception as e:
_complain("exception %r while fixing up sys.stdout and sys.stderr" % (e,))
# While we''re at it, let''s unmangle the command-line arguments:
# This works around <http://bugs.python.org/issue2128>.
GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(("CommandLineToArgvW", windll.shell32))
argc = c_int(0)
argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
argv = [argv_unicode[i] for i in xrange(0, argc.value)]
# argv = [argv_unicode[i].encode(''utf-8'') for i in xrange(0, argc.value)]
if not hasattr(sys, ''frozen''):
# If this is an executable produced by py2exe or bbfreeze, then it will
# have been invoked directly. Otherwise, unicode_argv[0] is the Python
# interpreter, so skip that.
argv = argv[1:]
# Also skip option arguments to the Python interpreter.
while len(argv) > 0:
arg = argv[0]
if not arg.startswith(u"-") or arg == u"-":
break
argv = argv[1:]
if arg == u''-m'':
# sys.argv[0] should really be the absolute path of the module source,
# but never mind
break
if arg == u''-c'':
argv[0] = u''-c''
break
# if you like:
sys.argv = argv
La pregunta se responde en el artículo PrintFails .
De forma predeterminada, la consola en Microsoft Windows solo muestra 256 caracteres (cp437, de la página de códigos 437 , el juego de caracteres ASCII extendido original IBM-PC 1981).
Para Rusia, esto significa CP866, otros países también usan sus propias páginas de códigos. Esto significa que para leer correctamente la salida de Python en la consola de Windows, debe tener la configuración de Windows con la página de códigos nativa configurada para mostrar los símbolos impresos.
Le sugiero que siempre imprima texto Unicode sin ninguna codificación para garantizar la máxima compatibilidad con varias plataformas.
Si intenta imprimir caracteres no imprimibles, obtendrá UnicodeEncodeError o verá texto distorsionado.
En algunos casos, si Python no puede determinar correctamente la codificación de salida, puede intentar establecer la variable de entorno PYTHONIOENCODING, pero tenga en cuenta que probablemente esto no funcione para su ejemplo, ya que su consola no puede presentar texto asiático en la configuración actual.
Para reconfigurar la consola, use el Panel de control-> Configuración regional y de idioma-> Avanzado (pestaña) -> Idioma de los programas no Unicode (sección). Tenga en cuenta que los nombres del menú los traduzco del ruso.
Ver también respuestas para la pregunta muy similar .
Simplemente proviene de esa consola cmd y powershell que no admite fuentes de ancho variable. Las fuentes fijas no tienen script chino incluido. Cygwin está en el mismo caso.
La masilla es más avanzada y admite fuentes de ancho variable con letras cirílicas, vietnamitas y árabes, pero hasta el momento no hay chino.
HTH
Use un programa de consola diferente. Lo siguiente funciona en mintty, el emulador de terminal predeterminado en Cygwin.
>>> print u"/u5f15/u8d77/u7684/u6216"
引起的或
Existen otras alternativas de consola disponibles para Windows, pero no he evaluado su compatibilidad con Unicode.