在 Java 中将 UTF-8 转换为 ISO-8859-1

2022-09-04 01:16:23

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

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

以下是我为尝试此操作而编写的代码片段:

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");

我已经阅读了以前关于这个主题的文章,我正在边走边学。提前感谢您的帮助。


答案 1

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

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

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());

上面,字符左双引号 ( ) 编码为 &#x201C;。其他几个任意码位也同样被编码。U+201C

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


答案 2

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

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

return new String(latin1);

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


推荐