工作中遇到,要拆分String成固定字节长度的几串字符。做法是转byte[],拆分后再转String返回数据,但拆分后的String字节长度并不是前面固定的值

需求分析

举个例子,一个String字符串要拆分成2个字符串,需要保证第一个字符串为5个字节,此处也只针对前半部分字符串进行讨论。

以前学C语言还记得英文字符占1个字节,中文占2个字节,到java变成英文字符占2个字节,但实际上是字符编码不同影响所占字节数。此文章以UTF-8为准,Java中汉字占3个字节。

代码分析

//原字符串
String str = "你是谁";
//原字符串全转为byte数组
byte[] b = str.getBytes("UTF-8");
//拆分的第一个byte数组,保证只有5个字节长度
byte[] b1 = new byte[5];
//将原byte数组复制前5个字节到拆分的第一个数组b1
for (int i = 0; i < 5; i++) {
    b1[i] = b[i];
};
//b1数组转为需要返回的前半部分字符串,按理说b1数组是5个字节,那么str1应该也是5个字节
String str1 = new String(b1, "UTF-8");
//对str1再次转换,转成byte[]
byte[] b2 = str1.getBytes("UTF-8");
//对相关数据输出展示
System.out.println("str原字符串:" + str);
System.out.println("str原字符串转换的byte数组b:" + Arrays.toString(b));

System.out.println("str前5个字节的byte数组b1:" + Arrays.toString(b1));
System.out.println("str拆分后的前半部分字符串str1:" + str1);

System.out.println("str1再次转为byte数组b2:" + Arrays.toString(b2));
System.out.println("str1再次转为byte数组b2的长度:" + b2.length);

可以看一下输出

str原字符串:你是谁
str原字符串转换的byte数组b:[-28, -67, -96, -26, -104, -81, -24, -80, -127]
str前5个字节的byte数组b1:[-28, -67, -96, -26, -104]
str拆分后的前半部分字符串str1:你�
str1再次转为byte数组b2:[-28, -67, -96, -17, -65, -67]
str1再次转为byte数组b2的长度:6

问题出现了,前5个字节转换成的字符串str1,再转成byte[]变成6个字节了。

原因:汉字3个字节,原字符串3个汉字,共9个字节,切割前5个必然会把一个汉字分割,切分后的5个字节前3个按照UTF-8还可以转换为汉字,但是后2个已经无法组成一个汉字,我猜测若UTF-8中没有这2个字节组成的字符就会变成乱码,导致再次转换出现异常。

小结

在进行转换时首先要确定字符编码,统一一种来进行开发,其次如果有切割字符串的操作(此处的切割指的是字节层面,并非单纯的切分),要尽量避免把一个汉字切分,可以适当移动字符串使得刚好不切割汉字。


小人物