有没有一种编程语言能够完全正确地跨平台支持Unicode?

5

这些年来,我使用过不少编程语言,同时也是一个爱好语言学并为Wiktionary做出贡献的业余学者。我一直在开发一些工具,以便从命令行查询Wiktionary,但遇到了意想不到的问题。

Perl和Python都不能在*nix和Windows下原生地将Unicode输出到控制台(虽然有各种解决方案)。主要原因是*nix操作系统喜欢UTF-8编码的Unicode,而Windows则喜欢UTF-16编码的Unicode。但似乎Windows很难使用宽字符与控制台交互,即使控制台和wprintf都支持宽字符

那么问题来了,如果我把目光放远一些,看看Java、C#、Scala等语言,情况会变得更好吗?或者有没有一些最初是在Windows上开发,后来又移植到*nix平台的脚本语言呢?

以下是一些理想的伪代码:

function main()
{
    print( L"hello, 世界" );
}

3
最终答案是任何语言最终都需要调用WriteConsoleW而不是WriteFile,打破了一个抽象屏障……因此这不是真正的语言问题,而是库设计问题。 - user541686
@Mehdrad:或许微软可以修复wprintf等函数,这样你就可以直接打印宽字符字符串而无需转换,除非这是C的wprintf或POSIX区域设置规范中的错误?或者,编程语言可以在它们的打印函数和WriteFile/WriteConsoleW或其他API之间添加一个抽象层。 - hippietrail
1
Windows控制台中的Unicode很难处理。虽然不像你链接的文章描述的那么难,但也不容易。其中一个问题是字体支持。即使你找到了wprintf正常工作的正确方法,你仍然会看到方块而不是中文字符。因此,问题不在于编程语言,而在于输出所使用的媒介。你可以考虑使用某种图形控制台(例如“Windows PowerShell ISE”)。 - Mihai Nita
3
基本问题在于Windows控制台模型已经失效。控制台不仅仅是一个普通的文件句柄,它是一个特殊设备,具有不同于普通文件句柄的API,不能很好地适应变成普通文件句柄。例如,如果您使用SetOutputCP(CP_UTF8)并尝试以不同的方式将UTF-8数据写入控制台,则会发现一些奇怪的行为。UTF-8输出可以通过fputs和其他一些API工作,但您无法像std::cout那样单独写入每个字节。 - bames53
1
请注意:win-unicode-console 可以透明地调用WriteConsoleW(),而不需要修改你的Python脚本(print(u"hello, 世界"))。 - jfs
显示剩余6条评论
4个回答

2

有没有一种语言能完全正确地处理Unicode和跨平台问题?

C#非常广泛地支持Unicode。它的标准库(.NET Framework)也对Unicode提供了出色的支持。跨平台方面相对来说是合理的,但并不完美:它是通过Mono实现的,在移动平台上则是通过Xamarin实现的。

命令行程序相当便携,但可能会受到古老遗物的影响,比如SSH终端已经十年或更久没有更新的情况。

下面是一些理想的伪代码:

C#接近完美:

using System;
class Program
{
    static void Main(string[] args)
    {
        Console.OutputEncoding = System.Text.Encoding.UTF8;
        Console.WriteLine("tést, тест, τεστ, ←↑→↓∏∑√∞①②③④, Bài viết chọn lọc");
    }
}

输出结果的截图(使用Consolas或其他具有上述字符的字体):

proof

当然,C#不是一种脚本语言;它在处理几乎所有事情时都非常不同。


0

八年半过去了,情况正在改善。

  • NodeJS是第一种可以在*nix、Mac和Windows上使用Unicode而不考虑操作系统是否偏好UTF-8或UTF-16的终端/控制台的语言。

  • 当我提出这个问题时,Perl、Python或Ruby都不能正常工作。我不确定PHP是否可以。但至少Python开发人员最终认真对待了相关的错误报告/功能请求,并进行了一些工作。Python现在已经在跨平台终端Unicode方面工作了几年。

  • 我刚开始研究Rust,并想检查一下这个问题。我非常高兴地发现他们也认真对待了这个问题,Rust是第一种低级别/非脚本语言,在Mac、Windows和*nix上可以轻松地跨平台使用控制台中的Unicode。


0
据我所知,几乎所有的脚本语言都起源于Unix世界,然后被移植到Windows。我不知道任何一个在Windows上开始的(脚本)语言……一种似乎对Unicode表现良好的脚本语言是Ruby。

我能想到的唯一在Windows上启动的脚本语言是Windows PowerShell,但与Perl和Python不同,它似乎更加针对脚本而非程序,并且非常晦涩。(-: - hippietrail
1
它似乎有一些很棒的功能(比如对象管道)......但它只能在Windows上使用,所以不算数 :-) - DarkDust
实际上,*nix有一个名为Pash的PowerShell,但我不是PowerShell专家,所以我没有尝试过:http://pash.sourceforge.net/ - hippietrail
由于Windows的WriteFile bug,Ruby在代码页65001下会破坏UTF-8的输出。我认为它根本不支持直接输出UTF-16。 - hippietrail

-1

也许这是你暗示的解决方法之一,但是:你可以在一个"DOS窗口"中使用非光栅字体选择并查看来自在Unix或Windows下运行的脚本(或程序)的UTF-8输出,并输入chcp 65001。代价是.bat/.cmd文件将无法执行。


2
"chcp 65001" 将“ANSI”编码设置为UTF-8,因此您可以使用UTF-8字符串的WriteConsoleA以及UTF-16字符串的WriteConsoleW。实际上,它似乎得到了很差的支持。它会导致Python崩溃,并使Perl输出看起来像是由于UTF-8字符串的字符长度和字节长度之间的差异而产生的工件。 - hippietrail
我进一步调查了这个问题,发现Windows的WriteFile() API存在一个错误,它返回的是代码页65001下的字符数,而不是文档中所述的字节数。这就是为什么在Windows上Perl、PHP和Ruby下的chcp 65001无法正常工作的原因。Python也有自己独立的错误。 - hippietrail

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接