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

时间:2011-02-09 07:23:36

标签: python windows perl unicode console

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

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

更新

似乎责任可能需要各方共同承担责任。我想象脚本语言只能在Windows上调用wprintf并让操作系统/运行时担心重定向等问题。但事实证明even wprintf on Windows converts wide characters to ANSI and back before printing to the console

请告诉我这是否已修复,因为错误报告链接似乎已损坏,但我的Visual C测试代码仍然无法用于wprintf并成功用于WriteConsoleW。

更新2

实际上,您可以使用wprintf从C打印UTF-16到控制台,但前提是_setmode(_fileno(stdout), _O_U16TEXT)

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

更新3

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

Python开发团队慢慢意识到自it was first reported back at the end of 2007以来这是一个真正的问题,并且已经看到了大量的活动,以便在2016年完全理解并完全修复该错误。

9 个答案:

答案 0 :(得分: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问题,大多数新手< em>仍然使用可怕的遗留API!)。

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

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

答案 1 :(得分:9)

对讨论的贡献很小 - 我正在运行捷克本地化的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";

答案 2 :(得分:7)

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

你知道吗

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

答案 3 :(得分:5)

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

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

答案 4 :(得分:4)

您确定您的脚本会在其他平台上正确输出Unicode吗? “广泛的印刷品”警告让我非常怀疑。

我建议您查看此overview

答案 5 :(得分:3)

  

这么多年后为什么要这样做呢   他们不只是简单地调用Win32 -W   输出UTF-16 Unicode的API   而不是强迫一切通过   ANSI /代码页瓶颈?

因为Perl和Python不是Windows程序。他们的Unix程序碰巧主要移植到Windows。因此,除非必要,否则他们不喜欢调用Win32函数。对于基于字节的I / O,没有必要;这可以通过Standard C Libary来完成。基于UTF-16的I / O是一种特殊情况。

  

或者-WAP本质上是坏的   达到他们无法做到的程度   按原样使用?

我不会说-WAP本质上已经破坏了,就像我说微软在C(++)中使用Unicode的方法本身已经被打破。

无论有多少Windows开发人员坚持认为程序应该使用wchar_t而不是char,切换的障碍太多了:

  • 平台依赖:
    • 在Windows上使用UTF-16 wchar_t,在其他地方使用UTF-32 wchar_t。 (新的char16_tchar32_t类型可能会有所帮助。)
    • UTF-16文件名函数的非标准性,如_wfopen_wstat等,限制了在跨平台代码中使用wchar_t的能力。
  • 教育。 Everbody用printf("Hello, world!\n");学习C,而不是wprintf(L"Hello, world!\n");。我在大学里使用过的C教科书在附录A.13中都没有提到过广泛的字符。
  • 使用char*字符串的现有数量的代码行。

答案 6 :(得分:2)

要让Perl以这种方式完全支持Windows,必须修改对print printf say warndie的每次调用。

  • 这是Windows?
  • 哪个版本的Windows? Perl仍主要适用于Windows 95
  • 这是进入控制台还是其他地方。

确定后,您必须使用完全不同的API函数集。

如果您真的希望看到正确执行此操作所涉及的所有内容,请查看sourceWin32::Unicode::Console


在Linux,OpenBSD,FreeBSD和类似操作系统上,您通常只需在STDOUTSTDERR文件句柄上调用binmode

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

这假设终端正在使用UTF-8编码。

答案 7 :(得分:2)

对于Python,跟踪器中的相关问题是http://bugs.python.org/issue1602(如评论中所述)。请注意,它开放7年。我尝试将一个有效的解决方案(根据问题中的信息)发布为Python包:https://github.com/Drekin/win-unicode-consolehttps://pypi.python.org/pypi/win_unicode_console

答案 8 :(得分:0)

Unicode issues in Perl

介绍了Win32控制台如何使用Perl以及从ANSI到Unicode的场景后面发生的转码;虽然不仅仅是Perl问题,还会影响其他语言