2009-08-13 3 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"); 

와 라틴 교체했다. 귀하의 도움에 미리 감사드립니다.

답변

12

이렇게 할 표준 라이브러리에 정규화 루틴이 있는지 확실하지 않습니다. 나는 "똑똑한"따옴표의 변환이 표준 Unicode normalizer 루틴에 의해 처리된다고 생각하지 않지만 나를 인용하지는 않습니다.

스마트 할 일은 ISO-8859-1을 덤프하고 UTF-8을 사용하는 것입니다. 즉, 일반적으로 허용되는 유니 코드 코드 포인트를 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 이중 인용 MARK (U+201C& #을 x201C;는) & #의 x201C로 인코딩됩니다 ; 두 개의 다른 임의 코드 포인트도 마찬가지로 인코딩됩니다.

이 방법으로주의를 기울여야합니다. 텍스트를 HTML 용으로 이스케이프해야하는 경우 위 코드를 수행하거나 앰퍼샌드를 이스케이프 처리해야합니다.

+0

작품 아름답게 . 고맙습니다! – Chocula

+0

방금 ​​이렇게 많은 슬픔을 덜어 줬습니다! – daniel0mullins

4

기본 인코딩에 따라, 다음 줄은, 문제가 자바에서

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

return new String(latin1); 

을 일으킬 수, 문자열/숯불는 UTF-16BE 항상. 문자를 바이트로 변환 할 때만 다른 인코딩이 필요합니다. 기본 인코딩이 UTF-8이고, latin1 버퍼가 UTF-8로 처리되고 Latin-1의 일부 시퀀스가 ​​잘못된 UTF-8 시퀀스를 형성 할 수 있다고하면?

1

String 객체를 인스턴스화 할 때 사용할 인코딩을 지정해야합니다.

그래서 대체 :

return new String(latin1); 

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

에 의해, 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; 
    } 
}