2009-08-13 31 views
11

我正在閱讀XML文檔(UTF-8)並最終使用ISO-8859-1在網頁上顯示內容。正如所料,有幾個字符不能正確顯示,如,(它們顯示爲?)。在Java中將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編碼?)。我嘗試另一個變化是與

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

我已閱讀關於這個問題以前的帖子,我學習,我去更換的latin1。在此先感謝您的幫助。

回答

12

我不確定在標準庫中是否有規範化例程會執行此操作。我不認爲標準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雙引號(U+201C&#x201C;)被編碼爲&#x201C ;。其他一些任意代碼點也被編碼。

需要注意這種方法。如果您的文本需要轉義爲HTML,則需要在上面的代碼或&符號最終被轉義之前完成。

+0

精美作品。謝謝! – Chocula 2009-08-13 23:05:24

+0

這只是給了我很多的傷心! – daniel0mullins 2013-01-25 19:42:40

4

根據您的默認編碼,下面的行可能會導致問題,

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

return new String(latin1); 

在Java中,字符串/字符總是UTF-16BE。只有在將字符轉換爲字節時纔會涉及到不同的編碼。假設您的默認編碼是UTF-8,latin1緩衝區被視爲UTF-8,並且某些拉丁文-1序列可能會形成無效的UTF-8序列,您將得到?。

1

當你實例化你的String對象時,你需要指明使用哪種編碼。

所以更換:

return new String(latin1); 

通過

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

使用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; 
    } 
}