Java如何判断一个字符是否由两个UTF-16码点组成?
判断Java中UTF-16双码点字符的方法
Java里的char类型采用UTF-16编码存储字符,对于Unicode码点超过U+FFFF的增补平面字符,会被拆分成两个char组成的代理对存储。比如你测试的字符𒌍(U+1230D),就被拆成了\uD808(高位代理)和\uDF0D(低位代理),单独打印这两个char时,因为它们本身不是有效的独立Unicode字符,所以会显示乱码。
怎么判断一个char属于代理对?
UTF-16的代理对有明确的数值范围和二进制特征:
- 高位代理:数值范围是
0xD800到0xDBFF,二进制格式为110110xx xxxxxxxx - 低位代理:数值范围是
0xDC00到0xDFFF,二进制格式为110111xx xxxxxxxx
Java的Character类已经封装好了现成的判断方法,直接调用即可:
Character.isHighSurrogate(char c):判断当前char是否是高位代理Character.isLowSurrogate(char c):判断当前char是否是低位代理Character.isSurrogate(char c):判断当前char是否是代理对中的任意一个
示例代码
用这段代码可以正确识别代理对并获取完整码点:
String s = "\uD808\uDF0D"; for (int i = 0; i < s.length(); ) { char current = s.charAt(i); if (Character.isHighSurrogate(current)) { // 找到高位代理,必须和下一个char组合成完整字符 char low = s.charAt(i + 1); int fullCodePoint = Character.toCodePoint(current, low); System.out.printf("找到代理对:高位0x%X,低位0x%X,对应完整码点U+%X%n", current, low, fullCodePoint); i += 2; // 跳过下一个char,因为已经组合过了 } else { System.out.printf("单码点字符:0x%X%n", current); i += 1; } }
UTF-16代理对的编码规则(翻译自相关维基内容)
对于Unicode码点在U+010000到U+10FFFF之间的字符,UTF-16用两个16位单元表示,转换逻辑是:
- 把目标码点减去
0x10000,得到一个20位的数值(范围是0到0xFFFFF) - 将这个20位数值拆分为高10位和低10位两部分
- 高10位加上
0xD800,得到高位代理的数值 - 低10位加上
0xDC00,得到低位代理的数值
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

