※ 引述《tripleleft (连续中离)》之铭言:
: 最近因为某些软件的风波
: 所以想自己写个连接PTT的软件
: 目前的写法是开一个新的Thread跑socket
: socket = new Socket(host, port);
:
: 然后参考版上读取的方法
: in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
: in.readLine();
: 不过编码一直出问题
: (使用String S = new String(in.readLine().getBytes(),"BIG5");)
: 所以把他拆开来读取
: byte[] data = in.readLine().getBytes();
: for循环跑S+= Byte.toString(data[num]) + ",";
: 然后把他印出来
: System.out.println(S);
: 然后就发现只要遇到中文字或全角符号他的编码就会变成-17 -65 -67(0xEF 0xBF 0xBD)
: (甚至不是偶数的倍数到底是怎么回事)
: 想问问到底是我写的问题有问题还是我编码的方式不对
new String(in.readLine().getBytes(),"BIG5");
这行看起来没什么问题,可能要直接把原始的 bytes 印出来才知道为什么不能转。
byte[] byteArray = new byte[] {(byte) 0xA4, (byte) 0xA4};
try {
String s = new String(byteArray, "Big5");
System.out.println(s);
System.out.println("length of s: " + s.length());
} catch (UnsupportedEncodingException e) {
}
上面可以印出:
中
1
参考 Big5 的 spec http://bit.ly/1GNtEO0
双色字需要特别处理。
以上面“中”的编码 0xA4A4 为例,
高位字节 A4 与低位字节 A4 在 Big5 的定义区间,
因此 new String(byteArray, "Big5") 这行会拿 0xA4A4 去 Big5 码表查对应的字。
而双色字,如“中”,当程式在解析 byte array 时,
遇到第一个 0xA4,因为 0xA4 不在 ASCII 编码中,
且符合 Big5 的高位字节,
所以预期下一个 byte 会符合 Big5 的低位字节。
但是下一个 byte 是 0x1B (ESC),
这不符合低位字节,
此时就会跳进特别的处理,
容错率高一点的话,
他可能会把 0xA4 0x1B 当成两个不可视的字符,
结果就是整个 array 转完后,不会有“中”这个字。
严谨一点来看,0xA4 0x1B 既不是合法的 Big5 编码,也不是合法的 ASCII 编码,
因此发生 exception 也是很合理的。
此外双色字并不存在于 Unicode 中也是一个问题。
new String(byteArray, "Big5") 这行会转两次码,
第一次去查 0xA4A4 是什么字,查到是“中”之后,
要作为 String 放在内存中,
此时会再查一次“中”在 Unicode 的编码是什么,
并在 String instance 中存入该 Unicode 编码。
另外 Byte.toString(byteArray[i]) 这样看不到是什么字很正常,
因为这样只是把 byte 转成 10 进位的数字再转成字串而已。
这样不会把 0xA4A4 当成一个字,只会当成 2 个 byte。