一个Java字符串中到底有多少个字符?( 二 )

  • Code Unit:代码单元 , 是指一个已编码的文本中具有最短的比特组合的单元 。对于 UTF-8 来说 , 代码单元是 8 比特长;对于 UTF-16 来说 , 代码单元是 16 比特长 。换一种说法就是 UTF-8 的是以一个字节为最小单位的 , UTF-16 是以两个字节为最小单位的 。
  • Java的字符在内部以UTF-16编码方式来表示 , String.length返回的是Code Unit的长度 , 而不再是Unicode中字符的长度 。对于传统的BMP平面的代码点 , String.length和我们传统理解的字符的数量是一致的 , 对于扩展的字符 , String.length可能是我们理解的字符长度的两倍 。
    有可能你会问 ,  对于一个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值 。
    我目前是在职Java开发 , 如果你现在正在了解Java技术 , 想要学好Java , 渴望成为一名Java开发工程师 , 在入门学习Java的过程当中缺乏基础的入门视频教程 , 你可以关注并私信我:01 。我这里有一套最新的Java基础JavaSE的精讲视频教程 , 这套视频教程是我在年初的时候 , 根据市场技术栈需求录制的 , 非常的系统完整 。

    【一个Java字符串中到底有多少个字符?】


    推荐阅读