为什么脚本语言不能将Unicode输出到Windows控制台?

hip*_*ail 19 python windows unicode console perl

Windows控制台至少可以识别十年,并且可能早在Windows NT上.但是由于某些原因,主要的跨平台脚​​本语言(包括Perl和Python)只输出各种8位编码,因此需要很多麻烦才能解决.Perl给出了"打印中的宽字符"警告,Python给出了一个charmap错误并退出.为什么在这么多年之后它们不仅仅是简单地调用输出UTF-16 Unicode的Win32 -W API而不是通过ANSI /代码页瓶颈强制一切?

仅仅是跨平台性能是低优先级吗?这些语言是否在内部使用UTF-8并且发现输出UTF-16太麻烦了?或者-WAP本身是否破坏到不能按原样使用的程度?

UPDATE

似乎责任可能需要各方共同承担责任.我想象脚本语言只能wprintf在Windows上调用,让操作系统/运行时担心重定向等问题.但事实证明,即使是Windows上的wprintf,也会在打印到控制台之前将宽字符转换为ANSI并返回!

如果这个问题已得到解决,请告诉我,因为错误报告链接似乎已损坏但我的Visual C测试代码仍然无法用于wprintf并成功用于WriteConsoleW.

更新2

实际上,您可以使用C语言将UTF-16打印到控制台,wprintf但前提是这样做_setmode(_fileno(stdout), _O_U16TEXT).

从C你可以将UTF-8打印到一个控制台,其代码页设置为代码页65001,但Perl,Python,PHP和Ruby都有防止这种情况的错误.Perl和PHP通过在包含至少一个宽字符的行之后添加额外的空行来破坏输出.Ruby的损坏输出略有不同.Python崩溃了.

更新3

Node.js是第一个没有出现此问题的脚本语言.

Python开发团队慢慢意识到这是一个真正的问题,因为它是在2007年底首次报道的,并且已经看到了大量的活动,以完全理解并完全修复2016年的错误.

Phi*_*ipp 20

主要问题似乎是在Windows上仅使用标准C库并且不依赖于平台或第三方扩展来使用Unicode是不可能的.您提到的语言源自Unix平台,其实现Unicode的方法与C很好地融合(它们使用普通char*字符串,C语言环境函数和UTF-8).如果你想在C中做Unicode,你或多或少要写两次:一次使用非标准的Microsoft扩展,一次使用标准的C API函数用于所有其他操作系统.虽然这可以做到,但它通常没有高优先级,因为它很麻烦,而且大多数脚本语言开发人员无论如何都讨厌或忽略Windows.

在更技术层面,我认为大多数标准库设计者所做的基本假设是所有I/O流本质上都是基于操作系统级别的字节,对于所有操作系统上的文件和Unix上的所有流都是如此.类似系统,Windows控制台是唯一的例外.因此,如果想要合并Windows控制台I/O,则必须在很大程度上修改许多类库和编程语言标准的体系结构.

另一个更主观的观点是,微软并不足以推广使用Unicode.第一个拥有体面(当时)Unicode支持的Windows操作系统是1993年发布的Windows NT 3.1,早在Linux和OS X增加Unicode支持之前.尽管如此,在这些操作系统中向Unicode的过渡更加无缝且没有问题.微软再次听取了销售人员而不是工程师的意见,并将技术上过时的Windows 9x保留到2001年; 而不是强迫开发人员使用干净的Unicode接口,他们仍然发布破碎的,现在不必要的8位API接口,并邀请程序员使用它(查看Stack Overflow上的一些最新的Windows API问题,大多数新手仍然使用可怕的遗留API!).

当Unicode问世时,许多人意识到它很有用.Unicode最初只是一个纯16位编码,所以很自然地使用16位代码单元.微软然后显然说"好吧,我们有这个16位编码,所以我们必须创建一个16位的API",没有意识到没有人会使用它.然而,Unix名人认为"我们如何以高效和向后兼容的方式将其集成到当前系统中,以便人们真正使用它?" 随后发明了UTF-8,这是一个杰出的工程.就像Unix创建时一样,Unix人们想的更多,需要更长时间,在经济上取得更少的成功,但最终做得恰到好处.

我无法对Perl发表评论(但我认为Perl社区中的Windows仇恨比Python社区更多),但对于Python,我知道BDFL(不喜欢Windows的人)也表示有足够的​​Unicode支持在所有平台上都是一个主要目标.

  • +1非常有用的信息可以解决经常让我感到沮丧的问题. (2认同)
  • @hippietrail:`wprintf`是标准C,但`_setmode`和`_fileno`不是.通常(但并非总是),Microsoft会使用下划线来预先添加非标准扩展.`iconv`不是C标准的一部分.Perl和Python都没有使用纯C而没有扩展,因为即使是一些非常常见的东西,如阅读目录内容或创建链接,也不包含在C标准中.Lua在其标准库中仅使用标准C函数,但即使这样,它也必须使用扩展来进行动态模块加载. (2认同)
  • 如果Perl和Python不使用Microsoft扩展进行Unicode输出,则必须自己完成.Windows中的控制台输出总是需要经过`WriteConsoleW`,没有别的办法.参见例如[这个长篇讨论](http://bugs.python.org/issue1602)(其中许多贡献者错误地认为Unicode在Windows控制台中不起作用或者与代码页有关).它包含[可能修复]的链接(http://tahoe-lafs.org/trac/tahoe-lafs/browser/src/allmydata/windows/fixups.py),但一般来说Python标准库必须是重写. (2认同)

bvr*_*bvr 9

对讨论的贡献很小 - 我正在运行捷克本地化的Windows XP,几乎每个地方都使用CP1250代码页.控制台的有趣之处在于它仍然使用传统的DOS 852代码页.

我能够制作非常简单的perl脚本,使用以下命令将utf8编码数据打印到控制台:

binmode STDOUT, ":utf8:encoding(cp852)";
Run Code Online (Sandbox Code Playgroud)

尝试了各种选项(包括utf16le),但只有上面的设置正确打印带有重音的捷克字符.

编辑:我玩了一点问题,发现Win32 :: Unicode.模块导出函数printW在输出和重定向中都能正常工作:

use utf8;
use Win32::Unicode;

binmode STDOUT, ":utf8";
printW "P?íliš žlu?ou?ký k?? úp?l ?ábelské ódy";
Run Code Online (Sandbox Code Playgroud)

  • 旧的IBM代码页(例如852)用于兼容性,因为它们包含许多旧的DOS应用程序中使用的图形字符 - 其中许多仍在使用中!更新的代码页(例如1250)是针对Windows引入的,不包括控制台应用程序所需的旧图形字符. (2认同)
  • @bvr:是的我得到同样的东西.我不确定它是100%Windows的错误还是Windows和Perl之间的某些交互,尽管我认为它是前者.我很确定这是由于字符串函数假设字节数等于字符数. (2认同)

dax*_*xim 7

我必须解决你的许多问题.

你知道吗

  • Windows使用UTF-16作为其API,但仍然默认使用用户空间中的各种"有趣"遗留编码(例如Windows-1252,Windows-1251),包括文件名,对于Windows的许多本地化而言是不同的?
  • 你需要对输出进行编码,并且通过locale pragma实现为系统选择适当的编码,并且有一个称为locale的POSIX标准,在其上构建它,并且Windows与它不兼容?
  • Perl曾经支持过所谓的"广泛"API吗?
  • Microsoft设法使UTF-8适应其字符编码的代码页系统,您可以通过发出适当的chcp 65001命令来切换终端吗?

  • 我不知道错误的错误信息会导致6次投票! (2认同)
  • *您是否知道Windows正式符合POSIX标准?*您是否知道代码页65001在Windows 7的控制台中完全坏了?Perl有点使用它,但似乎有一个字符长度与字节长度的错误导致额外的空白行和第二次输出长行的结尾.而Python只是崩溃了.如果它确实有效,我会认为它是一个有用的解决方法,但不是从所谓的跨平台脚​​本语言输出Unicode的真正解决方案. (2认同)

Sin*_*nür 5

迈克尔卡普兰有一系列关于cmd控制台和Unicode 的博客文章,可能提供信息(虽然没有真正回答你的问题):

PS:感谢@Jeff查找archive.org链接.

  • +1 Kaplan的博客是Windows Unicode问题必读的内容 (2认同)