Java中生僻汉字处理后变为乱码(?)的问题排查与修复咨询
Java生僻汉字「𡍼」乱码问题解析
在Java中处理生僻汉字「𡍼」时,出现字符变为?的乱码情况,测试代码及输出如下:
测试代码
public static void main(String[] args) throws UnsupportedEncodingException { String a1 = "𡍼"; System.out.println(a1 + ".charAt(0)=" + (a1.charAt(0) + 0)); StringBuffer a = new StringBuffer(); a.append("a=C0000002006人力資源處").append(a1.charAt(0)); PrintStream out = new PrintStream(System.out, true, "UTF-8"); out.println(a); System.out.println(a.toString()); StringBuffer b = new StringBuffer(); b.append("b=C0000002006人力資源處").append(a1.substring(0,1)); out.println(b); System.out.println(b.toString()); }
执行输出
𡍼.charAt(0)=55364 a=C0000002006人力資源處? a=C0000002006人力資源處? b=C0000002006人力資源處? b=C0000002006人力資源處?
原因分析
这不是Java的Bug,核心原因是「𡍼」属于Unicode辅助平面字符(代码点U+2137C),而Java的char类型是基于UTF-16编码的16位字符单元,辅助平面字符需要用**两个连续的char(代理对)**来表示:
a1.charAt(0)仅获取了代理对中的第一个高代理字符(值为55364,对应U+D844),这个单独的代理字符没有实际语义,无法被正确解析显示,因此输出为?。a1.substring(0,1)同样只截取了第一个代理字符,导致相同的乱码问题。
修复方案
要正确处理这类辅助平面字符,需要基于Unicode代码点而非16位char单元来操作,以下是几种可行的修复方式:
- 直接截取完整字符范围
由于「𡍼」占2个char单元,直接截取substring(0,2)即可获取完整字符:
StringBuffer b = new StringBuffer(); b.append("b=C0000002006人力資源處").append(a1.substring(0,2));
- 通过代码点转换为完整字符串
使用codePointAt获取完整代码点,再转换为char数组后拼接:
int codePoint = a1.codePointAt(0); char[] chars = Character.toChars(codePoint); StringBuffer a = new StringBuffer(); a.append("a=C0000002006人力資源處").append(chars);
- 遍历字符串的代码点
如果需要批量处理包含多个辅助平面字符的字符串,推荐使用codePoints()方法遍历:
StringBuilder sb = new StringBuilder(); sb.append("c=C0000002006人力資源處"); a1.codePoints().forEach(cp -> sb.append(Character.toChars(cp)));
修复后的输出示例
𡍼.charAt(0)=55364 a=C0000002006人力資源處𡍼 a=C0000002006人力資源處𡍼 b=C0000002006人力資源處𡍼 b=C0000002006人力資源處𡍼
内容的提问来源于stack exchange,提问作者Albert_you
相关产品推荐
相关产品推荐

