我知道如何使用特定编码将字符串转换为字节数组,但如何将字符索引转换为字节索引(在Java中)?
例如,在UTF-32中,字符索引i
是字节索引4 * i
,因为每个UTF-32字符都是4字节宽。但是在UTF-8中,大多数英文字符是1字节宽,大多数其他脚本中的字符是2或3字节宽,少数是4字节宽。对于给定的字符串和编码,我如何获得每个字符的起始字节索引数组?
这是我的意思的一个例子。 UTF-8中的字符串"Hello مرحبا こんにちは"
具有以下索引:[0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 17, 20, 23, 26, 29]
因为拉丁字符各为1个字节,阿拉伯字符各为2个字节,日语字符各为3个字节。 (在累积和之前,数组为[1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 3, 3, 3, 3, 3]
。)
Java中是否有库函数来计算这些索引位置?它需要高效,所以我不应该将每个字符转换为单独的字节数组,只是为了查询它的长度。根据Unicode的一些知识,有没有一种简单的方法可以自己计算它?通过识别指示下一个字符宽度的特殊字节,应该可以一次完成。
答案 0 :(得分:5)
我认为这可以做你想要的:
static int[] utf8ByteIndexes(String s) {
int[] byteIndexes = new int[s.length()];
int sum = 0;
for (int i = 0; i < s.length(); i++) {
byteIndexes[i] = sum;
int c = s.codePointAt(i);
if (Character.charCount(c) == 2) {
i++;
byteIndexes[i] = sum;
}
if (c <= 0x7F) sum += 1; else
if (c <= 0x7FF) sum += 2; else
if (c <= 0xFFFF) sum += 3; else
if (c <= 0x1FFFFF) sum += 4; else
throw new Error();
}
return byteIndexes;
}
给定一个Java字符串,它返回一个与String中每个char
对应的UTF-8字节索引的数组。
System.out.println(Arrays.toString(utf8ByteIndexes("Hello مرحبا こんにちは")));
输出:
[0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 17, 20, 23, 26, 29]
U + FFFF之上的异常Unicode字符,那些不适合Java的16位字符类型的字符,有点令人讨厌。例如,圣诞树表情符号U + 1F384()使用两个Java&#34; chars&#34;进行编码。对于那些,上面的函数为两个字符返回相同的字节索引:
System.out.println(Arrays.toString(utf8ByteIndexes("xy")));
输出:
[0, 1, 1, 5]
但总体累积字节数是正确的(如果以UTF-8编码,表情符号需要4个字节)。