一、名词解释
一个完整的Unicode字符叫代码点/CodePoint,而一个Java char 叫代码单元code unit;
代码点,是从Unicode标准而来的术语,Unicode标准的核心是一个编码字符集, 它为每一个字符分配一个唯一数字。Unicode标准始终使用16进制数字,并且在书写时在前面加上U+, 如字符“A”的编码为“U+0041”。
代码点是指可用于编码字符集的数字。编码字符集定义一个有效的代码点范围, 但是并不一定将字符分配给所有这些代码点。有效的Unicode代码点范围是U+0000至U+10FFFF。 Unicode4.0将字符分配给一百多万个代码点中的96382个代码点。
string对象以UTF-16保存Unicode字符,需要用2个字符表示一个超大字符集汉字,这种表示方式为 Sruuogate,第一个字符叫Surrogate High,第二个就是Surrogate Low 判断一个char是否是Surrogate区的字符,用Character的isHighSurrogate()/isLowSurrogate()方法。 从两个Surrogate High/Low字符,返回一个完整的Unicode CodePoint用Character.toCodePoint()/codePointAt() 一个Code Point,可能需要一个也可能需要两个char表示,因此不能直接使用CharSequence.length() 方法返回一个字符串到底有多少个汉字,而需要用String.codePointCount()/Character.codePointCount()。
二、CodePonits使用
要定位字符串中的第N个字符,不能直接将n作为偏移量,而需要从字符串头部依次遍历得到,需要 String.offsetByCodePoints()。
从字符串的当前字符,找到上一个字符,不能直接用offset实现,而需要 String.codePointBefore(),或String.offsetByCodePoints() 。
从当前字符,找下一个字符,需要判断当前CodePoint的长度,再计算得到 String.offsetByCodePoints()。
codePoint在Textview截取字符串(尤其是emoji表情)时特别有用,
public String ellipsizeText(TextView textView, String text) {
String tmpTxt = null;
if (textView != null && text != null) {
// 为了避免substring删除emoji等多个char的元素导致的错误截取
int codePointCount = text.codePointCount(0, text.length());
for (int i = codePointCount; i >= 0; i--) {
int offset = text.offsetByCodePoints(0, i);
if (StringUtil.isEmpty((tmpTxt = text.substring(0, offset)))
|| (textView.getPaint().measureText(tmpTxt) + textView.getPaddingLeft()
+ textView.getPaddingRight()) < textView.getWidth()) {
break;
}
}
}
return tmpTxt == null ? "" : tmpTxt;
}