【问题标题】:Converting UTF-8 to ISO-8859-1 in Java在 Java 中将 UTF-8 转换为 ISO-8859-1
【发布时间】:2010-11-19 10:15:36
【问题描述】:

我正在阅读一个 XML 文档 (UTF-8),并最终使用 ISO-8859-1 在网页上显示内容。正如预期的那样,有几个字符没有正确显示,例如(它们显示为?)。

是否可以将这些字符从 UTF-8 转换为 ISO-8859-1?

这是我编写的用于尝试此操作的 sn-p 代码:

BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
StringBuilder sb = new StringBuilder();

String line = null;
while ((line = br.readLine()) != null) {
  sb.append(line);
}
br.close();

byte[] latin1 = sb.toString().getBytes("ISO-8859-1");

return new String(latin1);

我不太确定出了什么问题,但我相信是 readLine() 导致了悲痛(因为字符串是 Java/UTF-16 编码的?)。我尝试的另一个变体是将 latin1 替换为

byte[] latin1 = new String(sb.toString().getBytes("UTF-8")).getBytes("ISO-8859-1");

我已阅读有关该主题的先前帖子,并且正在学习中。提前感谢您的帮助。

【问题讨论】:

    标签: java utf-8 character-encoding iso-8859-1


    【解决方案1】:

    我不确定标准库中是否有规范化例程可以执行此操作。我不认为“智能”引号的转换是由标准 Unicode normalizer 例程处理的——但不要引用我的话。

    明智的做法是转储ISO-8859-1 并开始使用UTF-8。也就是说,可以将任何通常允许的 Unicode 代码点编码为编码为ISO-8859-1 的 HTML 页面。您可以使用escape sequences 对它们进行编码,如下所示:

    public final class HtmlEncoder {
      private HtmlEncoder() {}
    
      public static <T extends Appendable> T escapeNonLatin(CharSequence sequence,
          T out) throws java.io.IOException {
        for (int i = 0; i < sequence.length(); i++) {
          char ch = sequence.charAt(i);
          if (Character.UnicodeBlock.of(ch) == Character.UnicodeBlock.BASIC_LATIN) {
            out.append(ch);
          } else {
            int codepoint = Character.codePointAt(sequence, i);
            // handle supplementary range chars
            i += Character.charCount(codepoint) - 1;
            // emit entity
            out.append("&#x");
            out.append(Integer.toHexString(codepoint));
            out.append(";");
          }
        }
        return out;
      }
    }
    

    示例用法:

    String foo = "This is Cyrillic Ya: \u044F\n"
        + "This is fraktur G: \uD835\uDD0A\n" + "This is a smart quote: \u201C";
    
    StringBuilder sb = HtmlEncoder.escapeNonLatin(foo, new StringBuilder());
    System.out.println(sb.toString());
    

    在上面,字符左双引号 (U+201C ) 被编码为 “。其他几个任意代码点也同样被编码。

    这种方法需要小心。如果您的文本需要为 HTML 进行转义,则需要在上述代码或 & 符号最终被转义之前完成。

    【讨论】:

    • 效果很好。谢谢!
    • 这让我省了很多苦头!
    • 请看看我在@robinst answer下的评论
    【解决方案2】:

    根据您的默认编码,以下行可能会导致问题,

    byte[] latin1 = sb.toString().getBytes("ISO-8859-1");
    
    return new String(latin1);
    

    在 Java 中,String/Char 始终采用 UTF-16BE。仅在将字符转换为字节时才涉及不同的编码。假设您的默认编码是 UTF-8,latin1 缓冲区被视为 UTF-8,某些 Latin-1 序列可能会形成无效的 UTF-8 序列,您会得到?。

    【讨论】:

      【解决方案3】:

      在 Java 8 中,McDowell's answer 可以这样简化(同时保留代理对的正确处理):

      public final class HtmlEncoder {
          private HtmlEncoder() {
          }
      
          public static <T extends Appendable> T escapeNonLatin(CharSequence sequence,
                                                                T out) throws java.io.IOException {
              for (PrimitiveIterator.OfInt iterator = sequence.codePoints().iterator(); iterator.hasNext(); ) {
                  int codePoint = iterator.nextInt();
                  if (Character.UnicodeBlock.of(codePoint) == Character.UnicodeBlock.BASIC_LATIN) {
                      out.append((char) codePoint);
                  } else {
                      out.append("&#x");
                      out.append(Integer.toHexString(codePoint));
                      out.append(";");
                  }
              }
              return out;
          }
      }
      

      【讨论】:

      • 我不确定这是否是对 Latin-1(ISO-8859-1) 符号的正确检查。我改用Charset.forName("ISO-8859-1").newEncoder().canEncode((char) codePoint) 作为检查,当然Charset.forName("ISO-8859-1").newEncoder() 被保存为常量或方法变量。
      【解决方案4】:

      当您实例化您的 String 对象时,您需要指出要使用的编码。

      所以替换:

      return new String(latin1);
      

      return new String(latin1, "ISO-8859-1");
      

      【讨论】:

        猜你喜欢
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-25
        • 2014-08-29
        • 2014-04-30
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        相关资源
        最近更新 更多