【问题标题】:getBytes() With UTF-8 Doesn't Work for Upper-Case German Umlauts带有 UTF-8 的 getBytes() 不适用于大写德语变音符号
【发布时间】:2012-09-03 19:52:59
【问题描述】:

对于开发,我使用ResourceBundle 直接从 IDE 的资源目录中读取 UTF-8 编码的属性文件(我在 Eclipse 的文件属性中设置了该文件)(native2ascii 用于生产方式),例如:

menu.file.open.label=&Öffnen...
label.btn.add.name=&Hinzufügen
label.btn.remove.name=&Löschen

由于在使用非 ASCII 字符时会导致字符编码出现问题,我认为我会很满意:

ResourceBundle resourceBundle = ResourceBundle.getBundle("messages", Locale.getDefault());
String value = resourceBundle.getString(key);
value = new String(value.getBytes(), "UTF-8");

嗯,它确实适用于小写的德语变音符号,但不适用于大写的,ß 也不起作用。这是用getString(key) 读取的值和用new String(value.getBytes(), "UTF-8") 转换后的值:

&Löschen => &Löschen
&Hinzufügen => &Hinzufügen

&Ã?ber => &??ber
&SchlieÃ?en => &Schlie??en
&Ã?ffnen... => &??ffnen...

最后三个应该是:

&Ã?ber => &Über
&SchlieÃ?en => &Schließen
&Ã?ffnen... => &Öffnen...

我想我离真相并不太远,但我在这里错过了什么?

Google 找到了 something similar,但仍未得到答复。

编辑:更多代码

【问题讨论】:

    标签: java character-encoding resourcebundle


    【解决方案1】:

    问题是您调用String.getBytes() 没有指定编码 - 这将使用默认平台编码。然后,您将使用该操作的二进制结果就好像它在 UTF-8 中一样。

    如果你双向使用 UTF-8 就可以了:

    // Should be a round-trip
    value = new String(value.getBytes("UTF-8"), "UTF-8");
    

    ...但是如果您尝试使用它来读取 UTF-8 编码的属性文件而不告诉执行 initial 读取的代码,那将无法正常工作。

    您提供的代码基本上是总是错误的方法。您的“因为这会导致字符编码出现问题”表明您已经遇到了较早的问题 - 所以我会回到那个问题,而不是尝试应用损坏的修复程序。如果您在构建ResourceBundle 时已经丢失了数据,那么稍后再返回就来不及了……您需要确保ResourceBundle 本身已正确加载。

    准确地告诉我们您在使用ResourceBundle 时遇到了什么问题,我们看看能否解决根本原因。

    编辑:目前尚不清楚您是如何运行 native2ascii 的。修复可能就像更改使用一样简单:

    native2ascii -encoding UTF-8 input.properties output.properties
    

    【讨论】:

    • @sjngm:嗯,它会带有往返代码,是的。这才是重点。您尝试的“修复”是试图从坏数据中制造好数据,但这是行不通的。 getBytes() 本身完全按照指定的方式工作 - 但你正在尝试做一些你不应该做的事情。停止这样做,并解释您正在尝试解决的问题。
    • 嗯,问题是小写的德语变音符号很好用。因此,我认为我没有做错一切。我不知道我怎么能以不同的方式告诉ResourceBundle。问题是它不适用于大写变音符号和“ß”。
    • @sjngm:你还没有告诉我们确实出了什么问题,或者你是如何诊断的。例如,如果您将其写入控制台,这很可能是问题所在,字符串中的字符完全正确。请向我们提供有关原始问题的详细信息 - 您看到了什么,在哪里看到它,您是如何诊断的,等等。
    • 我在我的问题中列出了它,其中带有“Löschen”的代码块是我尝试转换的输出,由ResourceBundle => new String(getBytes(), "UTF- 8")
    • @sjngm:输出在哪里?您是如何运行 native2ascii 的,请记住输入文件是 UTF-8(根据它的声音),不是您的本机编码。
    【解决方案2】:

    一些注意事项:

    • 如果是 String,则为 UTF-16,如果不是,则为损坏的字符串(修复为时已晚。)
    • new String(value.getBytes(), "UTF-8"); - 此代码(充其量)在使用 UTF-8 作为默认编码的系统上什么也不做;否则会损坏字符串。
    • .properties 文件必须是 ISO 8859-1(Properties 类型支持其他格式和编码,但我不知道你会如何告诉ResourceBundle。)
    • System.out 可能会引入自己的转码错误(PrintStream 将 UTF-16 字符串编码为默认编码;接收设备必须使用相同的编码解码字节。)

    我怀疑你试图在错误的地方解决你的问题。

    【讨论】:

      【解决方案3】:

      您正在使用与您正在解码的编码不同的编码对文本进行编码。

      尝试使用相同的字符集进行编码和解码。

      value = new String(value.getBytes("UTF-8"), "UTF-8");
      

      String s = "ßßßßß";
      s += s.toUpperCase();
      s = new String(s.getBytes("UTF-8"), "UTF-8");
      System.out.println(s);
      

      打印

      ßßßßßSSSSSSSSSS
      

      【讨论】:

      • 不,结果是原来的value
      • @sjngm 应该是这样。如果您将字符串编码为字节然后对其进行解码,您应该得到您开始的内容。你想发生什么?
      • 在来回转换 Java 变量时,它也适用于我。当我使用ResourceBundle 时它不会。
      【解决方案4】:

      今天我正在和我的一位同事交谈,他与其他答案提到的几乎相同。所以我试图实现 Jon Skeet 所提到的,这意味着创建与生产中相同的文件。由于在每次更改资源后重建项目是不可能的,而且我还没有做任何解决这个问题的方法(我想这对某些人来说是新的)让我把它排成一行(即使它可能只是为了个人参考 ;) )。简而言之,这使用了 Eclipse 的项目构建器。

      1. 创建一个 Ant 风格的 build.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <project>
            <property name="dir.resources" value="src/main/resources" />
            <property name="dir.target" value="bin/main" />
        
            <target name="native-to-ascii">
                <delete dir="${dir.target}" includes="**/*.properties" />
                <native2ascii src="${dir.resources}" dest="${dir.target}" includes="**/*.properties" />
            </target>
        </project>
        

        其目的是删除目标目录中的属性文件并使用native2ascii 重新创建它们。删除是必要的,因为native2ascii 不会覆盖现有文件。

      2. 在 Eclipse 中,转到项目属性并选择“Builders”,单击“New...”,选择“Ant Builder”(这是用于运行配置的略微增强的编辑器)
      3. 在“Main”中让“Buildfile”指向 Ant 脚本,将“Base Directory”设置为 ${project_loc}
      4. 在“刷新”中勾选“完成后刷新资源”并选择“包含所选资源的项目”
      5. 在“Targets”中,点击“Auto Build”旁边的“Set Targets”,然后在此处选择native-to-ascii(请注意,由于某种原因,我稍后不得不再次执行此操作)
      6. 这可能不是每个人都需要,但在“JRE”中选择合适的执行环境
      7. 在“构建选项”中勾选“分配控制台”(但是,您可能希望保持勾选状态,直到您看到一切正常为止)
      8. “应用”、“确定”
      9. 有人告诉我,新创建的构建器应该位于 Java Builder 下方(使用向上/向下按钮)
      10. 在“Java Build Path”中选择包含资源的源文件夹(我是src/main/resources)并为**/*.properties添加排除项

      应该是这样的。如果您编辑属性文件并保存它,它应该会在输出文件夹中自动转换为 ASCII。您可以尝试输入ü,最终应为\u00fc

      请注意,如果您有很多属性文件,这可能需要一些时间。只是不要在每次按键后保存。 :)

      【讨论】:

        猜你喜欢
        • 2010-11-10
        • 2013-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多