Windows控制台中的Unicode字符比预期的要多

9
我希望你能在Windows控制台中打印俄语和德语字符。为了测试这个功能,我编写了一个小程序:
PrintStream ps = new PrintStream(System.out, false, "UTF-8");
ps.println("öäüß гджщ");

然后我打开cmd.exe,将其字体更改为支持Unicode的Lucida Console,使用“chcp 65001”更改代码页为Unicode并执行我的程序。

德语和俄语字符被打印出来了,但比我预期的多了一点文字(用红线下划线标出): enter image description here

但在Eclipse控制台中,文本正确地被打印出来了。是否有方法可以在Windows控制台中正确打印它? 我使用的是Windows 7。

我刚刚通过JNI解决了这个问题,但仍然想知道是否可以使用纯Java解决。


1
我曾经在一段时间前看过这个链接(http://illegalargumentexception.blogspot.co.uk/2009/04/i18n-unicode-at-windows-command-prompt.html),但是从未找到它发生的原因。我猜想原因深藏在JRE本地代码中。 - McDowell
2
据我所知,这种行为取决于Windows版本。来自utf8everywhere.org的消息:“在Windows 7上,无论使用什么字体,控制台都会将该字符显示为两个无效字符。” - Pavel Radzivilovsky
@McDowell 我认为你是对的,问题一定在 JRE 中。 - ka3ak
@Pavel Radzivilovsky 您的诊断非常准确。也许没有其他解决问题的方法,只能使用 JNI 或 JNA。 - ka3ak
尝试使用SetConsoleOutputCP(CP_UTF8)并将输出设置为UTF-8。这应该可以解决问题。 - Pavel Radzivilovsky
@ka3ak,已经过去2年了,但在阅读Java文章时,我读到了以下内容:“System.console().printf(...)System.out.println(...)方法更好地支持特殊字符。”有关类似帖子,请参见:https://dev59.com/12865IYBdhLWcg3wEaQw - bvdb
3个回答

1
每次打开或写入文件时,都会应用某种编码。但有时我们忘记了我们的IDE(在您的情况下是Eclipse)也有一个编码。
当您在引号之间键入某些文本时,它将以某种编码显示和键入,即您的IDE的编码。 您的假设是输出流的编码(UTF-8)也将保证该文本以特定编码显示。然而,我认为这里再次应用了您的IDE的编码。
我建议您仔细检查Eclipse的编码设置。也许这可以解决您的问题。值得一试,不是吗? :)
要进行全局编码设置,请将以下代码添加到eclipse.ini文件中。
-Dfile.encoding=UTF-8 

编辑:

我想补充一下。我进行了以下实验步骤。

  1. 我打开了Notepad++并创建了一个新文件
  2. 我将编码设置修改为UTF-8
  3. 我复制了你的俄文文本并将其粘贴到我的新文本文件中并保存它。
  4. 接下来,我打开了我的Windows控制台(“cmd”)
  5. 我执行了“chcp 65001”命令。
  6. 接下来,我在控制台中打印了文件的内容:“type file.txt”
  7. 一切都显示正确。

这并没有证实太多,但它确实证实了一个事实,即如果内容以正确的编码预见,则DOS可以完成工作。

编辑2:

@ka3ak 已经过去两年多了,但是在阅读有关Java I/O的书籍时,我偶然发现了以下内容。

System.console().printf(...)方法比System.out.println(...)方法更好地支持特殊字符。

由于PrintStream只是包装了System.out流,我猜你会有同样的限制。我想知道这是否可以解决问题。如果还有问题,请尝试一下。:)

stackoverflow上的其他帖子也报告了类似的情况:console.writeline和System.out.println


我也尝试了你所做的步骤,结果和你一样。选项“-Dfile.encoding=UTF-8”没有起到帮助作用,我得到了同样错误的文本。 - ka3ak
@Bvdb - 问题出在 System.out 上,以及它如何写入标准输出流。默认情况下,它使用系统的传统 ANSI 编码。尝试使用 UTF-8 会导致不良行为。我还要指出,并非所有 JRE 库都会遵循 file.encoding 属性,因为它不是标准属性。 - McDowell
@McDowell 我刚在某个地方读到,System.console() 对特殊字符的支持比 System.out 流更好。从某种程度上来说,这有点像你两年前所说的。 :) - bvdb

0

在阅读这里的答案和建议后,我得出结论JRE必须存在问题。也许这个问题只存在于Windows 7中(不幸的是我没有其他Windows系统来进行实验)。

解决方案是使用JNI或者如果你想要一个更简单的解决方案,那么使用JNA。我在这里找到了一个有用的JNA示例,解决了我的问题,链接在这里https://dev59.com/4nVD5IYBdhLWcg3wNIrc#8921509


1
FYI:类似的行为至少可以追溯到Windows XP。 - McDowell

0

这是由于Windows中cp65001的¼-hearted实现。请参见@eryksun's answer中的完整披露。

简要概述:在Windows 7之前,只有7位(sic!)输入/输出在cp65001中可靠工作(除非CRTL进行了解决方案)。Windows 8已经修复了输出问题。Windows 10中存在输入问题。


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