最近,我在从字节到字符串的转换过程中遇到了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 ;字符。
背后的原因是什么?
最终,有没有办法保持字符串编码和解码机制之间的字节输入一致性?
答案 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不太可能这样做。
注意: