【问题标题】:Encoding strangeness with Cp500 (LF & NEL)用 Cp500 (LF & NEL) 编码奇怪
【发布时间】:2014-07-08 13:35:53
【问题描述】:

最近我在从字节转换为字符串然后从字符串转换为字节的过程中遇到了一个奇怪的 Cp500 (EBCDIC) 编码问题。

问题是一个特定字符 LINE FEED - LF - 0x25 在此转换期间被转换为此字符 NEW LINE - NEL - 0x15

下面的代码验证了这一点:

byte[] b25 = { 0x25 };
byte[] b4E = { 0x4E };

System.out.printf("\n0x25 in hex : <0x%02X>", b25[0]);
System.out.printf("\n0x4E in hex : <0x%02X>", b4E[0]);

String stringB25 = new String(b25, "Cp500");
String stringB4E = new String(b4E, "Cp500");

System.out.printf("\nOther way, 0x25 in hex : <0x%02X>", stringB25.getBytes("Cp500")[0]);
System.out.printf("\nOther way, 0x4E in hex : <0x%02X>", stringB4E.getBytes("Cp500")[0]);

输出:

0x25 in hex : <0x25>
0x4E in hex : <0x4E>
Other way, 0x25 in hex : <0x15>
Other way, 0x4E in hex : <0x4E>

为了理解这种行为,我查看了 IBM500.java 类,发现 0x15 和 0x25 字符映射到“\n”字符。

这背后的原因是什么?

最终,有没有办法在字符串编码和解码之间保持字节输入的一致性机制

【问题讨论】:

    标签: java encoding byte java-6 codepages


    【解决方案1】:

    考虑这段代码:

      public static void main(String[] args) {
        transcode();
        System.setProperty("ibm.swapLF", "true");
        transcode();
      }
    
      private static void transcode() {
        byte EBCDIC_NL = 0x15; //next line
        byte EBCDIC_LF = 0x25; //line feed
        byte EBCDIC_CR = 0x0D; //carriage return
    
        ebcdicToUtf16(EBCDIC_NL);
        ebcdicToUtf16(EBCDIC_LF);
        ebcdicToUtf16(EBCDIC_CR);
    
        utf16ToEbcdic("\u0085"); //next line
        utf16ToEbcdic("\n"); //line feed
        utf16ToEbcdic("\r"); //carriage return
      }
    
      private static void ebcdicToUtf16(byte... b) {
        String utf16 = new String(b, Charset.forName("IBM500"));
        System.out.format("%02x -> %04x%n", b[0] & 0xFF, utf16.charAt(0) & 0xFFFF);
      }
    
      private static void utf16ToEbcdic(String s) {
        byte[] b = s.getBytes(Charset.forName("IBM500"));
        System.out.format("%04x -> %02x%n", s.charAt(0) & 0xFFFF, b[0] & 0xFF);
      }
    

    在 IBM JVM (1.7) 上运行时,会发出:

    15 -> 000a
    25 -> 000a
    0d -> 000d
    0085 -> 15
    000a -> 15
    000d -> 0d
    15 -> 000a
    25 -> 000a
    0d -> 000d
    0085 -> 15
    000a -> 25
    000d -> 0d
    

    This IBM JVM patch SI23602 解释:

    附加背景:行业中有两个标准 EBCDIC 处理换行函数。这两个标准是使用 LF (0x25) CDRA 或 NL (0x15) MVS 开放版。的早期版本 Java(从 JDK 1.3 开始)在换行符的使用上不一致 使用 0x15 与大多数 EBCDIC 编码一起工作,而其他一些 使用 0x25。从 JDK 1.4 开始,IBM JDK 选择了 使用 NL (0x15) 标准化所有 EBCDIC 字符编码。

    为了解决用于换行功能的双重标准,这 APAR 将提供一个开关,允许某些 EBCDIC 转换器 在使用 0x15 或 0x25 作为换行函数之间交换。默认 所有 EBCDIC 字符编码的行为将保持映射 unicode \u000A 字符到 EBCDIC 0x15 字符。指定 java 属性"ibm.swapLF=true" 将导致转换器切换 它的 unicode \u000A 到 EBCDIC 0x25 的映射。转换器 支持此 java 属性作为开关的有:Cp284、Cp285、Cp500、 Cp1140、Cp1141、Cp1142、Cp1143、Cp1144、Cp1145、Cp1146、Cp1147、 CP1148,CP1149。

    这两种设置都不会将任何内容映射到 U+0085(assigned Unicode value for NL/NEL)。大概这是出于历史原因 - ASCII 没有 NEL 字符,EBCDIC 到 ASCII 一定是比较常见的。

    可以实现到 Unicode 编码的无损往返,但 commonly available encoders 不太可能做到这一点。

    注意事项:

    【讨论】:

    • 解释得很好。使用 IBM JDK 时,ibm.swapLF 的作用就像一个魅力。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2014-05-25
    • 1970-01-01
    • 2016-10-02
    • 2016-12-01
    相关资源
    最近更新 更多