你真的懂 Unicode 编码吗?,理解 spring 原理哪本书好
Java 中的 UTF-8 其实和 mysql 的 uft8 都只能表示 3 个字节的字符,而 Java 中拥有和 utf8mb4 字符集一样表示范围的是 UTF-32 字符集。
于是我抱着尝试的心理,做了以下的 debug 调试:
UTF-32 和 UTF-8 不同,它是一个定长的字符集,什么叫定长呢?比如 UTF-8 字符集就比较鸡贼,如果是“1”这样的数字,他在 UTF-8 字符集中映射数字为 47,完全在 2 的 8 次方的表示范围内,也就说只要一字节就能满足了,这个时候 UTF-8 就把它转化成一字节的 byte[],而对于映射成几千几万的汉字来说,UTF-8 就会用长度为 2 或 3 的 byte[]来表示。而 UTF-32 就很“老实”了,无论你映射成的数字是 47,还是 47000,还是更大,他都用长度为 4 的 byte[]来表示(所以我们一般用 UTF-8,因为 UTF-32 会浪费很多内存空间)。
上图所示的,uft32BytesLength 的值为 28,可以反推出,UTF-32 判断的这个 mileage 字符串里面包含 7 个字符,也就是说,他把"??"准确地判断为是一个字,而不是两个普通字合在一起!
既然 JDK 能识别特殊字符,那我们学习源码怎么写的不就好了。
于是从 String#getBytes()方法一层层往下点,到最底一层,如下图:
JDK 就是通过这个方法来判断某个字符是普通字符还是属于特殊字符的一部分!
再点进去看这个方法:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201010141706176.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG
9nLmNzZG4ubmV0L3dlaXhpbl80OTUyNzMzNA==,size_16,color_FFFFFF,t_70#pic_center)
这两段英文大致意思就是:
决定入参是否为 unicode 的代码单元,满足条件的字符并不是单独表示一个字,而是用来表示 UTF-16 的增补字符。
如上图所示,凡是落在’\uD800’到’\uDFFF’,也就是 55296 到 57343 之间的字符都是用来两两表示特殊字符的!
代码如下:
public String filterUtf8mb4Character(String input) {
List<Character> list = Lists.newArrayList();
char[] charArray = input.toCharArray();
for (char c : charArray) {
if (!Character.isSurrogate(c)) {
list.add(c);
}
}
char[] outputArray = new char[list.size()];
for (int i = 0; i < list.size(); i++) {
outputArray[i] = list.get(i);
}
return new String(outputArray);
}
任何小问题只要肯钻研都会有不一样的收获,这也是决定大神和普通程序员的一个标准。
评论