Java字符串(Windows环境下)中的字符“æ”、“ø”和“æ”

15
由于某些原因,使用Scanner类分配字母å的字符串与使用“常规”方式分配å的字符串不相等:String a =“å” - 为什么会这样?
import java.util.*;

public class UTF8Test {
public static void main(String [] args) {

    String [] Norge = {"løk", "hår", "vår", "sær", "søt"};

    Scanner input = new Scanner(System.in);

    String  test = input.nextLine();  //I enter løk here
    System.out.println(test);
    System.out.println(Norge[0]);

    for(int i = 0; i < Norge.length; i++) {
        if(Norge[i].equals(test) ) {
            System.out.println("YES!!");
        }
    }
}
}

编译器将显示如下内容:

løk

løk

l├©k


@BalusC 我没有确保从 System.in 读取的字符使用 UTF-8 进行解释。我应该怎么做? - Sing Sandibar
此外,你说“编译器会显示这个”需要三行,但是你列出的输出似乎与你的代码不符。 - LordOfThePigs
2
取决于运行时环境。├© 作为 ø 的乱码形式表明原始环境使用的是 CP850 而不是 UTF-8。Windows 命令控制台默认使用 CP850。这表明您在 Windows 命令控制台中运行,而不是在像 Eclipse 这样支持 UTF-8 的 IDE 中运行。您可以通过打印/检查 Charset.defaultCharset() 的结果来确认这一点。 - BalusC
1
编译器在运行时/输入/输出过程中根本不起作用。编译器仅在将.java文件转换为.class文件时起作用。 - BalusC
也许有人应该尝试检查一下.class文件,看看编译器如何在其输出中表示字符串。 - AJMansfield
显示剩余9条评论
5个回答

7

如果您的唯一要求是在UTF8Test类名所示的“任何地方”使用UTF-8,则您的主要错误是使用Windows命令控制台来编译和运行Java程序。 ├©作为ø糊状形式,强烈表明您正在使用CP850编码来编译Java源代码文件。 作为证据,在支持UTF-8的环境中运行此命令:

System.out.println(new String("ø".getBytes("UTF-8"), "CP850"));

这会打印出 ├©。这表明您使用的是Windows命令控制台编译Java源代码文件,因为这是当前唯一默认使用CP850的常用环境。然而,Windows命令控制台不支持UTF-8。
当您在文本编辑器中使用UTF-8编码保存(从字符转换为字节)源代码文件时,字符ø会被转换为字节0xC30xB8(证据见"UTF-8 (hex)" entry in U+00F8 character info)。当您运行javac UTF8Test.java时,UTF-8保存的源代码文件基本上是使用CP850编码读取的(从字节转换为字符)。这些字节0xC30xB8在此编码中代表字符©(证据见CP850 codepage layout)。这完全解释了您最初的问题。

的确,你可以通过-encoding UTF-8参数指示javac使用UTF-8读取源代码文件。然而,Windows命令控制台本身不支持UTF-8格式的输入和输出。当你使用-encoding UTF-8重新编译时,由于命令控制台无法正确表示UTF-8格式的输出,你仍将得到乱码输出。我在这里尝试过,结果得到了一个度符号:

løk
l°k

如果你打算在所有地方都使用UTF-8并想继续使用Windows命令控制台作为输入/输出环境,则无法解决这个问题。基本上,你需要一个支持UTF-8格式的输入/输出环境。像Eclipse和Netbeans这样的IDE就是这样的环境。或者,如果你打算将其作为一个支持UTF-8的独立程序运行,则应优先使用Swing UI而不是无GUI的控制台程序。


如果您打算将其作为独立程序运行,使用Swing UI应优于无GUI控制台程序。但实际上并非如此。任何可以成为无GUI控制台程序的东西都应该是这样。如果您想要GUI,则编写第二个程序,将GUI输入提供给第一个程序公开的API即可。 - AJMansfield
你的回答比我的更详细易懂,虽然最终答案相同,但我还是更喜欢你的 :-) - LordOfThePigs
@Ingo:不,Windows代码页65001通常不适用于控制台窗口。控制台窗口可能会任意吞噬跟在不希望的字符后面的输出。而且输入根本不起作用。 - Cheers and hth. - Alf

4

如果您想要一个带特殊字符的字符串,可以尝试使用Unicode转义:

String [] Norge = {"l\u00F8k", "h\u00E5r", "v\u00E5r", "s\u00E6r", "s\u00F8t"};

虽然在源代码中包含特殊字符(至少在java中)并没有错误,但是在某些情况下,它可能会导致编辑器、编译器或终端配置不良而出现问题;如果可能的话,个人建议尽量避免使用特殊字符。

顺便说一句,在Java源代码中,您还可以在javadoc注释以及类、方法和变量名称中使用Unicode转义。

如果您从命令行进行编译,可以使用-encoding选项将编译器配置为接受UTF-8,并将UTF-8作为其参数。如下所示:

javac -encoding UTF-8 ...

您可能会发现这个问题有用:Java中的特殊字符


您可以考虑将字符串外部化,作为解决问题的另一种方式。Eclipse 提供了自动执行此操作的方法,但它基本上只是将所有文字字符串放入单独的文件中,并从该文件中读取以获取适当的字符串。这还允许您创建程序的翻译,通过创建一个包含所有字符串翻译的不同文件,或者重新配置应用程序消息而无需重新编译。


编辑:我刚刚尝试在 Eclipse 中编译和运行它,没有遇到你提到的问题。因此,这很可能是您特定设置的问题。

当我将其重新配置为将代码编译为 US-ASCII 时,两次输出都是 l?k

当我将其重新配置为编译代码为 UTF-8 时,输出为 løkløk

当我将其编译为 UTF-16 时,输出为 þÿ l ø kløk,但是我无法从终端复制 þÿ l ø k 中的空格:它只让我复制前两个,然后剩下的就没有了。这可能与您遇到的问题有关 - 它们可能是一些控制字符,在您的情况下会出现问题。


2
原帖的具体问题并不是由于错误保存源代码文件引起的。此外,现在已经不是1990年了。现代编辑器使用UTF-8保存源代码文件。您仍然没有回答具体的问题。 - BalusC
@BalusC 这可能是由于这个原因引起的,你永远不知道。虽然字符串外部化仍然很好。 - AJMansfield
@BalusC 阅读 http://stackoverflow.com/questions/12445635/special-character-in-java。 - AJMansfield

3

在Windows中,默认情况下,Java编译器使用“平台默认编码”来解释其所有源文件。根据你运行编译器的环境,这可以是ISO-8859-1、CP1252、UTF-8或任何其他编码。

如果你正在使用的编辑器实际上使用UTF-8对Java源文件进行编码,但是编译器正在使用另一种编码读取这些源文件,则所有硬编码字符串的内容可能会出现问题(就像你经历过的那样)。要解决此问题,请确保将Java源文件保存为“平台默认编码”,或设置你的Java编译器以将源文件解释为UTF-8。

尝试使用javac -encoding UTF-8 UTF8Test.java调用编译器。如有必要,请确保将UTF-8替换为你的编辑器用于保存源文件的编码。


ø 的 ISO-8859-1-mojibaked 变体是 ø。然而,OP 得到了一个 ├©。因此,你的答案基本上是错误的。证据:System.out.println(new String("ø".getBytes("UTF-8"), "ISO-8859-1"));(在支持 UTF-8 的环境中执行!) - BalusC
嗯,如果这个人正在使用挪威代码页,他实际上可能正在使用ISO-8859-4或ISO-8859-10。我不确定这些应该如何翻译,但我仍然认为这是可能的。 - LordOfThePigs
抱歉,任何ISO-8859-X的乱码变体的2字节UTF-8字符都以Ã(0xC3)开头。 - BalusC
哦,你认为另一端的编码有问题?如果是这种情况,那么Norge [0]不是应该正确打印吗?我相信System.out确实使用默认的平台字符集,不是吗?或者是Windows命令提示符特别愚蠢,使用另一种编码而无法处理Java打印到其中的内容? - LordOfThePigs
@BalusC:我稍微修改了我的答案,删除了关于错误编码的引用。现在看起来更正确了吗?不过概念仍然是一样的。 - LordOfThePigs

1
如果您在使用Eclipse进行编程,需要更改控制台编码,请按照以下步骤操作:RUN菜单 > Run configurations.. > Common选项卡(右侧)> 在编码面板中选择 Other=UTF-8。请注意保留HTML标签。

enter image description here


-1

我遇到了显示挪威字符的问题。尝试使用编码:ISO 8859-10


这听起来不相关,因为OP想要使用UTF-8。 - Stephen Ostermiller

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