我正在尝试生成随机的Unicode字符串。我想指定每个字符占用的字节数(1-4个字节,因为我想将它们最终转换为UTF-8字节数组),以及字符数。例如,如果我指定10作为我的字符串中的字符数,3作为每个字符的字节数,我应该得到一个字符串str,当我调用时
str.getBytes(StandardCharsets.UTF_8).length
我应该得到30个字节。
我的代码使用1,2和4个字节为字符生成正确的字符串。但是,对于从0x800到0xffff的代码点,当我在返回的字符串上调用getBytes时,每次都会得到不同的字节数。任何想法为什么会这样?
private String generateRandomString(int numberOfCharacters, int bytesPerCharacter) {
int start;
int end;
switch (bytesPerCharacter) {
case 1:
start = 0;
end = 0x7f;
break;
case 2:
start = 0x80;
end = 0x7ff;
break;
case 3:
start = 0x800;
end = 0xffff;
break;
case 4:
start = 0x10000;
end = 0x10ffff;
break;
default:
throw new ArgumentException("Invalid value for the bytes per character");
}
StringBuilder builder = new StringBuilder(numberOfCharacters);
int count = 0;
int range = end - start;
for (int i = 0; i < numberOfCharacters; i++) {
builder.appendCodePoint((int) (Math.random() * range + start));
}
return builder.toString();
}
答案 0 :(得分:1)
非常有趣的问题
答案是,某些生成的代码点不是有效的Unicode,而Java知道这一点,当编码为UTF-8时将其替换为?
,这会抛出计数,因为只输出一个字节对于那些代码点,而不是三个。
public static void main(String[] args) {
int start = 0x800;
int end = 0xffff;
int range = end-start;
StringBuilder b = new StringBuilder();
for (int i=0; i<20; i++)
{
int a = (int)(Math.random() * range + start);
b.appendCodePoint(a);
System.out.printf("Code point %5d length=%d\n", a, b.length());
}
byte[] result = b.toString().getBytes(StandardCharsets.UTF_8);
System.out.println(result.length);
for (byte x : result)
{
// newline before any byte matching 1110 xxxx (start of 3-byte UTF-8)
if ((x & 0xF0) == 0xE0) System.out.println();
System.out.printf("%02x ", x);
}
System.out.println();
}
在某些运行中,这会产生少于60个字节,例如这个:
Code point 35798 length=1
Code point 30523 length=2
Code point 43674 length=3
Code point 2743 length=4
Code point 64416 length=5
Code point 2438 length=6
Code point 15808 length=7
Code point 56254 length=8
Code point 20690 length=9
Code point 48789 length=10
Code point 52635 length=11
Code point 9128 length=12
Code point 8445 length=13
Code point 27765 length=14
Code point 63710 length=15
Code point 53350 length=16
Code point 41031 length=17
Code point 25939 length=18
Code point 56414 length=19
Code point 46327 length=20
56
e8 af 96
e7 9c bb
ea aa 9a
e0 aa b7
ef ae a0
e0 a6 86
e3 b7 80 3f
e5 83 92
eb ba 95
ec b6 9b
e2 8e a8
e2 83 bd
e6 b1 b5
ef a3 9e
ed 81 a6
ea 81 87
e6 95 93 3f
eb 93 b7
注意UTF-8和0x3f = ?
的十六进制转储中只有18行。在第8和第19个位置查找生成的“代码点”显示这些是无效的Unicode代码点。
您无法生成随机整数值,并希望它们都是有效的Unicode。对包含此类代码点的String
进行编码会将无效代码点编码为0x3f
('?'
)。