代码之家  ›  专栏  ›  技术社区  ›  Chocula

在Java中转换UTF-8到ISO-859-1

  •  12
  • Chocula  · 技术社区  · 17 年前

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

    我不太清楚发生了什么,但是我相信这是导致悲伤的RealLoad(),因为字符串是Java/UTF16编码的?.我尝试的另一个变体是用

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

    我读过以前关于这个主题的文章,现在正在学习。事先谢谢你的帮助。

    4 回复  |  直到 10 年前
        1
  •  14
  •   McDowell rahul gupta    13 年前

    我不确定标准库中是否有一个规范化例程可以做到这一点。我不认为“智能”报价的转换是由标准来处理的。 Unicode normalizer 例行公事——但不要引用我的话。

    明智的做法是丢弃 ISO-8859-1 并开始使用 UTF-8 . 也就是说,可以将任何通常允许的Unicode代码点编码为 ISO-8859-1 . 您可以使用 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());
    

    上面,字符左双引号( U+201C “ )编码为&x201c;。其他一些任意的代码点也同样被编码。

    这种方法需要小心。如果您的文本需要为HTML转义,那么需要在上述代码或符号被转义之前完成。

        2
  •  4
  •   ZZ Coder    17 年前

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

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

    在爪哇,String/Char总是在UTF 16BE中。只有在将字符转换为字节时才涉及不同的编码。假设您的默认编码是utf-8, latin1 缓冲区被视为utf-8,拉丁语-1的某些序列可能形成无效的utf-8序列,您会得到吗?.

        3
  •  2
  •   Community Mohan Dere    9 年前

    用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;
        }
    }
    
        4
  •  1
  •   fbaligand    14 年前

    当您声明您的字符串对象时,您需要指出要使用哪种编码。

    所以替换:

    return new String(latin1);
    

    通过

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