最近,只有我注意到,有可能substring返回带有无效 unicode 字符的字符串。
例如
public class Main {
public static void main(String[] args) {
String text = "_Salade verte";
/* We should avoid using endIndex = 1, as it will cause an invalid character in the returned substring. */
// 1 : ?
System.out.println("1 : " + text.substring(0, 1));
// 2 :
System.out.println("2 : " + text.substring(0, 2));
// 3 : _
System.out.println("3 : " + text.substring(0, 3));
// 4 : _S
System.out.println("4 : " + text.substring(0, 4));
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道,当用 修剪长字符串时String.substring,有哪些好方法可以避免返回的子字符串包含无效的unicode?
Bas*_*que 16
char过时的该类型自Java 2以来char一直是遗留类型,基本上已被破坏。作为16 位值,物理上无法表示大多数字符char。
您的发现表明该String#substring命令是char基于的。因此,您的代码中显示了问题。
相反,在处理单个字符时应使用代码点整数。
\nint[] codePoints = "_Salade".codePoints().toArray() ;\nRun Code Online (Sandbox Code Playgroud)\n\n\n[129382、95、83、97、108、97、100、101]
\n
提取第一个字符\xe2\x80\x99s 代码点。
\nint codePoint = codePoints[ 0 ] ;\nRun Code Online (Sandbox Code Playgroud)\n\n\n129382
\n
String为该代码点创建一个单字符对象。
String firstCharacter = Character.toString( codePoint ) ; \nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n
int[] firstFewCodePoints = Arrays.copyOfRange( codePoints , 0 , 3 ) ;\nRun Code Online (Sandbox Code Playgroud)\n并String从这些代码点创建一个对象。
String s = \n Arrays\n .stream( firstFewCodePoints ) \n .collect( StringBuilder::new , StringBuilder::appendCodePoint , StringBuilder::append )\n .toString();\nRun Code Online (Sandbox Code Playgroud)\n\n\n_S
\n
或者我们可以使用 的构造函数String来获取数组的子集。
String result = new String( codePoints , 0 , 3 ) ;\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n_S
\n
Basil 的答案很好地表明您应该使用代码点而不是chars。
AString内部不存储 Unicode 代码点,因此在不检查字符串的实际内容的情况下,无法知道哪些字符属于一起形成 Unicode 代码点。
这是一个支持 Unicode 的子字符串方法。由于codePoints()返回 an IntStream,我们可以利用skipandlimit方法来提取字符串的一部分。
public static String unicodeSubstring(String string, int beginIndex, int endIndex) {\n int length = endIndex - beginIndex;\n int[] codePoints = string.codePoints()\n .skip(beginIndex)\n .limit(length)\n .toArray();\n return new String(codePoints, 0, codePoints.length);\n}\nRun Code Online (Sandbox Code Playgroud)\n这就是上述代码片段中发生的情况。我们流式传输 Unicode 代码点,跳过第一个beginIndex字节并将流限制为endIndex \xe2\x88\x92 beginIndex,然后将 b 转换为int[]. 结果是 int 数组包含从beginIndex到endIndex 的所有 Unicode 代码点所有 Unicode 代码点。
最后,该类String包含一个很好的构造函数,可以String从int[],因此我们使用它来获取字符串。
当然,您可以通过拒绝越界值来将该方法调整得更严格一些:
\nif (endIndex < beginIndex) {\n throw new IllegalArgumentException("endIndex < beginIndex");\n}\nint length = endIndex - beginIndex;\nint[] codePoints = string.codePoints()\n .skip(beginIndex)\n .limit(length)\n .toArray();\nif (codePoints.length < length) {\n throw new IllegalArgumentException(\n "begin %s, end %s, length %s".formatted(beginIndex, endIndex, codePoints.length)\n );\n}\nreturn new String(codePoints, 0, codePoints.length);\nRun Code Online (Sandbox Code Playgroud)\n\n
| 归档时间: |
|
| 查看次数: |
770 次 |
| 最近记录: |