一个字符串中到底能有多少个字符?我竟然算错了( 二 )


有可能你会问 ,  对于一个UTF-16编码的扩展字符 , 它以4个字节来表示 , 那么前两个字节会不会和BMP平面冲突 , 导致程序不知道它是扩展字符还是BMP平面的字符?
其实是不会的 ,  幸运的是 ,  在BMP平面中 ,  U+D800到U+DFFF之间的码位是永久保留不映射到Unicode字符 , UTF-16就利用保留下来的0xD800-0xDFFF区块的码位来对辅助平面的字符的码位进行编码 。
UTF-16编码中 , 辅助平面中的码位从U+10000到U+10FFFF , 共计FFFFF个,需要20位来表示 。第一个整数(两个字节 , 称为前导代理)要容纳上述20位的前10位 , 第二个整数(称为后尾代理)容纳上述20位的后10位 。前导代理的值的范围是0xD800到0xDBFF,后尾代理的0xDC00~0xDFFF 。
可以看到前导代理和后尾代理的范围都落在了BMP平面中不用来映射的码位 , 所以不会产生冲突 , 而且前导代理和后尾代理也没有重合 。这样我们得到两个字节的 , 就可以直接判断它是否是BMP平面的字符 , 还是扩展字符中的前导代理还是后尾代码 。
国外的有些用户用emojis字符做自己的昵称 , 导致有些系统不能正确的显示出来 , 这是因为这些系统粗暴的使用Charactor来表示 , 在显示的时候截断的时候有时候可能不是在正确的代码点上进行截断 。
我们在进行字符串截取的时候,比如String.substring有可能会踩到一些坑 , 尤其经常使用的emojis字符 。
自 Java 1.5 java.lang.String就提供了Code Point方法 ,  用来获取完整的Unicode字符和Unicode字符数量:
public int codePointAt(int index)public int codePointBefore(int index)public int codePointCount(int beginIndex, int endIndex)注意这些方法中的index使用的是code unit值 。




推荐阅读