ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Unicode编码 字符串截取

Unicode编码 字符串截取 这取决于你的截取需求是按码点字符数截取还是按原始 char 索引截取但保证安全。下面给出三种场景的正确写法1. 按字符数截取最常用用户说取前5个字应该指5个码点而不是5个charpublic static String substringByCodePoint(String s, int maxCodePoints) { return s.codePoints() .limit(maxCodePoints) .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) .toString(); } // 示例 String s ABC; // 5个码点7个char substringByCodePoint(s, 3); // AB ✅ 不会切断代理对⚠️注意codePoints()返回的是IntStream不能用普通的String拼接必须用appendCodePoint。2. 按 char 索引截取但保证边界安全当你拿到的就是 char 索引比如正则匹配返回的 offset需要确保不切断代理对public static String safeSubstring(String s, int beginIndex, int endIndex) { // 修正起始点如果落在低代理上向前扩展到完整字符 if (beginIndex 0 beginIndex s.length() Character.isLowSurrogate(s.charAt(beginIndex))) { beginIndex--; } // 修正结束点如果落在高代理上向后扩展到完整字符 if (endIndex s.length() Character.isHighSurrogate(s.charAt(endIndex))) { endIndex; } return s.substring(beginIndex, endIndex); } // 示例 String s AB; // char: [A, \uD83D, \uDE00, B] safeSubstring(s, 0, 2); // 原本会切在代理对中间 → 自动修正为 A ✅3. Java 21 推荐直接用String新方法Java 21 引入了原生码点感知 API彻底告别手动处理// 按码点数截取等价于方案1但更简洁 s.translate(0, 3); // 取前3个码点 // 获取码点长度 s.codePointCount(0, s.length()); 如果你还在 Java 8~17用方案1和方案2即可。 三种方案对比方案适用场景优点缺点codePoints().limit()按字符数截取语义清晰绝对安全有流式开销不适合高频调用边界修正 substring已有 char 索引时安全截取零额外分配性能好需手动处理两个边界Java 21translate新项目原生支持最简洁需要 JDK 21⚠️ 常见错误写法务必避免// ❌ 直接用 length 和 substring s.substring(0, Math.min(n, s.length())); // ❌ 用 charAt 逐字遍历计数 int count 0; for (int i 0; i s.length() count n; i, count) { } // ❌ 用 toCharArray() 再 new String(chars, 0, n)这些写法在遇到增补字符时一定会出问题。 核心原则先明确截取单位是什么。业务语义上的字/字符 → 用码点方案1或3底层协议/偏移量 → 用 char 索引 边界修正方案2永远不要混用两者选对你的场景直接复制对应方案即可。
返回列表