获取字符长度的正确姿势

public static void main(String[] args) throws UnsupportedEncodingException {
    String a="\uD864\uDD00";
    System.out.println(a.length()); //结果是2
    System.out.println(a.codePointCount(0, a.length())); //结果是1  这个才要正确姿势
    System.out.println(a.getBytes("utf8").length);  //结果是4
}

这里的\uD864\uDD00 ,对应的中文是参照https://segmentfault.com/q/1010000003757947

length 为什么会不对呢,length其实是char数组的长度。char是16位,最多也就是能表示65536个字符,中文都不只65536个,所以一个char是表示不了一个中文的。
更具体来说,char是 UTF-16 编码的结果,UTF-16其实也是变长的,一个到两个字符,有的时候会两个char表示一个字符

有的人说可以用getBytes("utf8"),这个也是很不靠谱的,虽然多数中文的结果都是3,但是有少部分是4的。对于非中文更加可能是1或者2

所以获取字符个数应该用codePointCount。
这UTF-16的编码规则,超出一个char的时候,是有特殊表示的,
具体地说保留了 D800-DFFF 共 2048 个位置:

D800-DBFF为高位  1024

DC00-DFFF 为地位 1024

1024*1024 = 一百万  够用了



static int codePointCountImpl(char[] a, int offset, int count) {
    int endIndex = offset + count;
    int n = count;
    for (int i = offset; i < endIndex; ) {
        if (isHighSurrogate(a[i++]) && i < endIndex &&
            isLowSurrogate(a[i])) {
            n--;  //这里是重点,有高地位的时候减1,做了修正
            i++;
        }
    }
    return n;
}

public static boolean isHighSurrogate(char ch) {
    // Help VM constant-fold; MAX_HIGH_SURROGATE + 1 == MIN_LOW_SURROGATE
    return ch >= MIN_HIGH_SURROGATE && ch < (MAX_HIGH_SURROGATE + 1);
}

public static final char MIN_HIGH_SURROGATE = '\uD800';

public static final char MAX_HIGH_SURROGATE = '\uDBFF';



可以看到codePointCount 的原理其实就是对于UTF-16的高地位(两个char的情况)做了修正的

你可能感兴趣的:(获取字符长度的正确姿势)