Java 错误地读取 System.in 中的重音字符

问题描述 投票:0回答:1

如果您面临同样的问题,并且您的字符集包含在 ANSI 测试编码(代码页 1252 或“ISO 8859-1”)中,您可以使用该编码来暂时规避 UTF-8 问题,但是UTF-8 是现代标准,涵盖了最终本地化的每个脚本。

我正在创建一个应用程序,它必须从控制台读取包含重音字符的用户输入。根据我在网上阅读的内容,现代控制台能够处理重音字符输出,并正确编码输入,即使它们在发送命令之前显示为

?

PS C:\> echo ?
ü
Ps C:\>

注意:此行为在命令提示符中不可重现。在 Windows 终端中运行时,命令提示符似乎也在发送之前正确显示重音字符。

但是,当运行下面的测试代码时:

package com.test.outputtest;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.nio.file.*;

public class OutputTest {

    public static void main(String[] args) {
        // Set I/O to use UTF-8
        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8));

        // Create the response listener
        Scanner input = new Scanner(System.in, StandardCharsets.UTF_8);

        System.out.println(Arrays.toString("èéëê".getBytes(StandardCharsets.UTF_8)));
        String temp = input.nextLine();
        System.out.println(Arrays.toString(temp.getBytes(StandardCharsets.UTF_8)));
    }

}

这是输出(构建工件“app.jar”之后):

PS C:\Users\[name]\Desktop\output_test> chcp 65001
Active code page: 65001
PS C:\Users\[name]\Desktop\output_test> java "-Dfile.encoding=UTF-8" -jar app.jar
[-61, -88, -61, -87, -61, -85, -61, -86]
èéëê
[0, 0, 0, 0]

第一个字节数组来自预先写好的字符串,第二个数组是输入字符串的字节。

echo
正确输出重音这一事实让我相信这是一个编译器错误,但我不确定如何修复它。我试过用
Scanner
替换
Console
,这给了我同样的错误。

在 IntelliJ 内部运行时,在终端中输入 ü 时可以正常读取它。这也是我怀疑编译时有问题的一个原因。 当使用命令提示符而不是 PowerShell 运行时,会发生同样的错误。

注意:我正在使用运行 PowerShell 的 Windows 终端和 IntelliJ Idea Community Edition 2021.3。除了工件构建文件路径和其他一些项目特定的文件路径之外,我还没有编辑

.xml
文件。

  • 操作系统:Windows 10 build 19045.2728
  • Java 版本:17.0.6(也在 IntelliJ 中)
  • 默认代码页:850(OEM)
  • 错误发生时使用的代码页:65001 (UTF-8)
java terminal utf-8 java.util.scanner system.in
1个回答
0
投票

我可以重现你的问题,但我看不出你的代码有什么问题,而且我没有简单的解决方案。令人难以置信的是,即使使用最新版本的 Java(18、19、20),从 Windows 控制台读取 UTF-8 字符似乎仍然存在问题。

这在 JDK bug JDK-8295672 中有正式记录,提供了一个更好的替代方法来读取 System.in,这是开放且未解决的。它指出(加上我的重点):

Reading

System.in
是有问题的,因为它是一个编码为 主机的编码。对于 JEP 400,有些情况下 默认编码 (UTF-8) 和主机的本机编码不同。读书 字节正确,用户必须转换字节 native-to-default,这似乎是基本使用的障碍。 提供更好的访问方式(不考虑编码内容) 会很合适。

因此将默认字符集设置为 UTF-8 并不能解决问题,因为“主机的本机编码” 不是 UTF-8,您对此无能为力(至少对于 cmd.exePowerShell 在 Windows 上)。

备注:

在整个标准 Java API 中对 UTF-8 进行标准化,除了 控制台 I/O.

  • 大概是由于上面提到的“主机编码”问题,控制台I/O被排除在JEP400中。
  • 一个明显的问题是为什么你的代码在 Intellij 中运行时可以工作?我怀疑这是因为 JetBrains 使用 JNA 从他们的控制台读取输入,但这只是一个猜测。
© www.soinside.com 2019 - 2024. All rights reserved.