我正在阅读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编码的?)。我尝试的另一个变体是用
替换latin1byte[] latin1 = new String(sb.toString().getBytes("UTF-8")).getBytes("ISO-8859-1");
我已经阅读过关于这个主题的帖子,我正在学习。在此先感谢您的帮助。
答案 0 :(得分:14)
我不确定标准库中是否存在执行此操作的规范化例程。我不认为“智能”引号的转换是由标准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());
在上面,字符LEFT DOUBLE QUOTATION MARK(U+201C
“)被编码为&amp;#x201C;。同样编码了几个其他任意代码点。
需要注意这种方法。如果您的文本需要针对HTML进行转义,则需要在上述代码或“&”符号被转义之前完成。
答案 1 :(得分:4)
根据您的默认编码,以下行可能会导致问题,
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序列,您将得到?。
答案 2 :(得分:2)
使用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;
}
}
答案 3 :(得分:1)
当您实例化String对象时,需要指明要使用的编码。
所以替换:
return new String(latin1);
通过
return new String(latin1, "ISO-8859-1");