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

Windows控制台至少有十年的时间可以识别Unicode,也许早于Windows NT。 然而,由于某些原因,包括Perl和Python在内的主要跨平台脚本语言只能输出各种8位编码,需要解决很多麻烦。 Perl给出了“宽字符打印”的警告,Python给出了charmap错误并退出。 为什么这些年来他们不只是简单地调用输出UTF-16 Unicode的Win32-W API,而不是通过ANSI /代码页瓶颈强制所有内容?

仅仅是跨平台性能低优先级? 是否这些语言在内部使用UTF-8,并且发现它太费心地输出UTF-16了? 或者-W API固有地破坏到不能原样使用的程度?

UPDATE

看起来责任可能需要各方共同分享。 我想到脚本语言只能在Windows上调用wprintf ,并让操作系统/运行时间担心诸如重定向之类的事情。 但事实证明,甚至在打印到控制台之前,即使Windows上的wprintf也将宽字符转换为ANSI并返回!

请让我知道,如果这已被修复,因为错误报告链接似乎损坏了,但我的Visual C测试代码仍然失败了wprintf并成功WriteConsoleW。

更新2

实际上,你可以使用wprintf从C打印UTF-16到控制台,但只有在你首先执行_setmode(_fileno(stdout), _O_U16TEXT)

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

更新3

Node.js是第一种没有直接提供这个问题的脚本语言。

Python开发团队慢慢意识到这是一个真正的问题,因为它是在2007年底首次报告的,并且在2016年发现了大量的活动来充分理解和完全修复该错误。


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

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

另一个更主观的观点是,微软并没有足够的推动Unicode的使用。 第一个Windows体系(支持其时代)Unicode支持的Windows操作系统是在1993年发布的Windows NT 3.1,早在Linux和OS X增加对Unicode的支持之前。 尽管如此,在这些操作系统中向Unicode的过渡却更加无缝和无争议。 微软再次听取销售人员而不是工程师的意见,并将技术上过时的Windows 9x保存到2001年; 与其迫使开发人员使用干净的Unicode接口,他们仍然提供已破损且现在不需要的8位API接口,并邀请程序员使用它(请参阅堆栈溢出最近的一些Windows API问题,大多数新手仍然使用可怕的遗留API!)。

当Unicode出来时,许多人意识到它很有用。 Unicode开始是一种纯粹的16位编码,所以使用16位代码单元是很自然的。 然后,微软显然说:“好的,我们有这个16位编码,所以我们必须创建一个16位API”,并没有意识到没有人会使用它。 然而,Unix专业人士认为“我们如何能够以高效且向后兼容的方式将其融入当前系统,以便人们实际使用它?” 并随后发明了UTF-8,这是一个精彩的工程。 就像Unix创建时一样,Unix的人们想得更多,需要更长的时间,财务上的成功更少,但最终做到了正确。

我无法对Perl进行评论(但我认为Perl社区中存在比Python社区更多的Windows仇恨),但关于Python,我知道BDFL(谁不喜欢Windows)已经说明了足够的Unicode支持在所有平台上都是主要目标。


对讨论的小小贡献 - 我正在运行捷克本地化的Windows XP,它几乎在任何地方都使用CP1250代码页。 控制台有趣的是它仍然使用传统的DOS 852代码页。

我能够使用非常简单的perl脚本将utf8编码数据输出到控制台:

binmode STDOUT, ":utf8:encoding(cp852)";

尝试了各种选项(包括utf16le),但只有以上设置才能正确打印重音捷克语字符。

编辑:我打了更多的问题,并发现Win32 :: Unicode。 该模块导出可在输出和重定向中正常工作的printW函数:

use utf8;
use Win32::Unicode;

binmode STDOUT, ":utf8";
printW "Příliš žluťoučký kůň úpěl ďábelské ódy";

我不得不回答你的许多问题。

你知道吗

  • Windows为其API使用UTF-16,但仍默认使用用户空间中的各种“有趣”传统编码(例如Windows-1252,Windows-1251),包括文件名,对于Windows的许多本地化而言都不同。
  • 你需要对输出进行编码,并且为系统选择合适的编码是通过语言环境编译指示来实现的,并且有一个叫做locale的POSIX标准,在这个标准上构建它,而Windows与它不兼容?
  • Perl曾经支持过所谓的“宽”API吗?
  • 微软设法将UTF-8转换为字符编码的代码页系统,并且可以通过发出适当的chcp 65001命令来切换终端。
  • 链接地址: http://www.djcxy.com/p/52285.html

    上一篇: Why don't scripting languages output Unicode to the Windows console?

    下一篇: Node.js: Count the number of lines in a file