【问题标题】:ISO-8859-1 encoding and binary data preservationISO-8859-1 编码和二进制数据保存
【发布时间】:2013-04-02 06:30:44
【问题描述】:

我在comment 中读到@Esailija 对我的一个问题的回答

ISO-8859-1 是唯一完全保留原始二进制数据的编码,具有精确的字节代码点匹配

我还在@AaronDigulla 的answer 中读到:

在 Java 中,ISO-8859-1(又名 ISO-Latin1)是 1:1 映射

我需要对此有所了解。这将失败(如图所示here):

// \u00F6 is ö
System.out.println(Arrays.toString("\u00F6".getBytes("utf-8")));
// prints [-61, -74]
System.out.println(Arrays.toString("\u00F6".getBytes("ISO-8859-1")));
// prints [-10]

问题

  1. 我承认我不太明白 - 为什么它没有得到上面代码中的字节
  2. 最重要的是,这是在哪里字节保留行为 ISO-8859-1指定 - 指向源代码的链接,或者 JSL 会很好。它是唯一具有此属性的编码吗?
  3. 是否与ISO-8859-1default default 有关?

另请参阅this question,了解其他字符集的精彩反例。

【问题讨论】:

  • -10 是 0xF6 的以 10 为底的有符号值。试试byte b = -10; System.out.println(Integer.toHexString(b & 0xFF));
  • @JBNizet :我知道 - 我要问的是引用的“ISO-8859-1 是在 java 中完全保留原始二进制数据的唯一编码” - 这就是我不太了解的得到 - 你给的东西打印 f6 - "\u00F6" 中包含的字节是什么? [-61, -74] 或 [-10] ?
  • 呃,你刚才说你知道-10和f6是同一个字节,表示不同。所以 0x00F6 中包含的字节是 0 是基数 16 中的 F6,或有符号基数 10 中的 0 和 -10。
  • @JBNiz :为什么它不打印 [0, -10] - 假设 ISO-8859-1 是字节保留 - 这就是我没有得到的 - 报告的“字节保留”行为ISO-8859-1 在java中的。
  • 好的。现在我明白你的意思了。看我的回答。

标签: java character-encoding iso-8859-1


【解决方案1】:

"\u00F6" 不是字节数组。它是一个包含单个字符的字符串。改为执行以下测试:

public static void main(String[] args) throws Exception {
    byte[] b = new byte[] {(byte) 0x00, (byte) 0xf6};
    String s = new String(b, "ISO-8859-1"); // decoding
    byte[] b2 = s.getBytes("ISO-8859-1"); // encoding
    System.out.println("Are the bytes equal : " + Arrays.equals(b, b2)); // true
}

要检查这是否适用于任何字节,只需改进代码循环遍历所有字节:

public static void main(String[] args) throws Exception {
    byte[] b = new byte[256];
    for (int i = 0; i < b.length; i++) {
        b[i] = (byte) i;
    }
    String s = new String(b, "ISO-8859-1");
    byte[] b2 = s.getBytes("ISO-8859-1");
    System.out.println("Are the bytes equal : " + Arrays.equals(b, b2));
}

ISO-8859-1 是一种标准编码。所以使用的语言(Java、C# 或其他)并不重要。

这是一个Wikipedia reference,声称覆盖了每个字节:

在 1992 年,IANA 注册了字符映射 ISO_8859-1:1987,通常以其首选的 MIME 名称 ISO-8859-1(注意 ISO 8859-1 上的额外连字符)而闻名,它是 ISO 8859- 的超集1、用于上网。此映射将 C0 和 C1 控制字符分配给未分配的代码值因此通过每个可能的 8 位值提供 256 个字符。

(强调我的)

【讨论】:

  • 谢谢 - 这回答 1 - 我真的需要一些权威链接来确定/拒绝 2) - 或一些解释 - 即 ISO-8859-1 的字节保留行为 - 它是唯一的 (在 java 和可能的其他语言中,我猜想像 C#)。对于其他字符集,请参阅:stackoverflow.com/questions/2544965/…
  • 谢谢 - 你相信它是 only ENCODING 与此属性:byte[] b = newByteArray(); Arrays.equals(b, new String(b, ENCODING).getBytes(ENCODING)); // always true 吗?
  • 不知道是不是只有一个,没有。
  • @Mr_and_Mrs_D 它是唯一一个解码后的代码点的值也是从中解码的字节值 (\u00F6 &lt;-&gt; 0xF6)。我正是这个意思。所以你有解码的字符串和编码的字节,那么对于任意二进制数据,它总是(byte)str.charAt(i) == bytes[i],其中strnew String(bytes, "ISO-8859-1")
  • @Mr_and_Mrs_D 它也是一种罕见的属性,但对于无损往返而言并非 ISO-8859-1 所独有:字节 -> 字符串 -> 具有任意二进制数据的字节。
【解决方案2】:

为了保留原始二进制数据的编码,它需要将每个唯一的字节序列映射到唯一的字符序列。

这排除了所有多字节编码(UTF-8/16/32、Shift-Jis、Big5 等),因为并非每个字节序列在其中都有效 因此会解码为一些替换字符(通常是 ? 或 �)。无法从字符串中看出是什么原因造成的 解码后的替换字符。

另一种选择是忽略无效字节,但这也意味着无限不同 字节序列解码为相同的字符串。您可以用十六进制编码替换无效字节 在像"0xFF" 这样的字符串中。无法判断原始字节是否合法解码 到"0xFF" 这样也不起作用。

这留下了 8 位编码,其中每个序列只是一个字节。单字节有效 如果有它的映射。但是很多 8 位编码都有漏洞,不能编码 256 个不同的字符。

要保留原始二进制数据,您需要对 256 个不同字符进行编码的 8 位编码。 ISO-8859-1 这不是唯一的。但它的独特之处在于解码后的代码点的值也是字节的值 它是从中解码出来的。

所以你有解码的字符串和编码的字节,那么它总是

(byte)str.charAt(i) == bytes[i] 

对于任意二进制数据,其中strnew String(bytes, "ISO-8859-1")bytesbyte[]


它也与 Java 无关。我不知道他的评论是什么意思,这些是字符编码而不是编程语言的属性。

【讨论】:

  • 该评论旨在将这一切放在代码透视图中(另请注意“在 Java 中,ISO-8859-1(又名 ISO-Latin1)是 1:1 映射”)- 也就是我没有不知道这一切在 C 中会是什么样子 - 非常有用的答案@JBNizet(“但它的独特之处在于,解码的代码点的值也是它解码的字节值”)+1 :)
猜你喜欢
  • 2011-02-12
  • 2011-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2018-02-21
  • 2012-02-17
相关资源
最近更新 更多