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

我正在阅读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"); 

我已经读过以前关于这个主题的post,我正在学习。 在此先感谢您的帮助。

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

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

 public final class HtmlEncoder { private HtmlEncoder() {} public static  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()); 

在上面,字符LEFT DOUBLE QUOTATION MARK( U+201C )被编码为&#x201C;。 同样编码了几个其他任意代码点。

需要注意这种方法。 如果您的文本需要针对HTML进行转义,则需要在上述代码或“&”符号被转义之前完成。

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

 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序列,你会得到?。

使用Java 8, McDowell的答案可以像这样简化(同时保留对代理对的正确处理):

 public final class HtmlEncoder { private HtmlEncoder() { } public static  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; } } 

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

所以替换:

 return new String(latin1); 

通过

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