用Cp500编码奇怪(LF& NEL)

时间:2014-07-08 13:35:54

标签: java encoding byte java-6 codepages

最近,我在从字节到字符串的转换过程中遇到了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字符映射到&#34; \ n&#34 ;字符。

背后的原因是什么?

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

1 个答案:

答案 0 :(得分:2)

考虑以下代码:

  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不太可能这样做。

注意: