如何生成包含增补字符的随机 Unicode 字符串?
How to generate a random Unicode string including supplementary characters?
我正在编写一些用于生成随机字符串的代码。生成的字符串似乎包含无效的 char
组合。具体来说,我找到了没有跟随低代理人的高代理人。
谁能解释为什么会这样?我是否必须显式生成随机低代理来跟随高代理?我以为这不需要,因为我使用的是 Character
class.
的 int
变体
这是测试代码,最近 运行 产生了以下错误配对:
配对错误:d928 - d863
配对错误:da02 - 7bb6
配对错误:dbbc - d85c
配对错误:dbc6 - d85c
public static void main(String[] args) {
Random r = new Random();
StringBuilder builder = new StringBuilder();
int count = 500;
while (count > 0) {
int codePoint = r.nextInt(Character.MAX_CODE_POINT + 1);
if (!Character.isDefined(codePoint)
|| Character.getType(codePoint) == Character.PRIVATE_USE) {
continue;
}
builder.appendCodePoint(codePoint);
count--;
}
String result = builder.toString();
// Test the result
char lastChar = 0;
for (int i = 0; i < result.length(); i++) {
char c = result.charAt(i);
if (Character.isHighSurrogate(lastChar) && !Character.isLowSurrogate(c)) {
System.out.println(String.format("Bad pairing: %s - %s",
Integer.toHexString(lastChar), Integer.toHexString(c)));
}
lastChar = c;
}
}
可以随机生成高或低代理项。如果这导致低代理项,或者高代理项后面没有跟随低代理项,则结果字符串无效。解决方案是简单地排除所有代理人:
if (!Character.isDefined(codePoint)
|| (codePoint <= Character.MAX_CHAR && Character.isSurrogate((char)codePoint))
|| Character.getType(codePoint) == Character.PRIVATE_USE) {
continue;
}
或者,它应该只查看从 getType
返回的类型:
int type = Character.getType(codePoint);
if (type == Character.PRIVATE_USE ||
type == Character.SURROGATE ||
type == Character.UNASSIGNED)
continue;
(从技术上讲,您还可以允许随机生成高代理项并添加另一个随机低代理项,但这只会创建其他随机代码点 >= 0x10000,这可能又是未定义的或供私人使用。)
您需要排除所有代孕孤儿(即高代孕和低代孕)。
仅供参考,UnicodeData.txt 的下一段摘录显示了代理项的代码点间隔:
D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;;
DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;
我正在编写一些用于生成随机字符串的代码。生成的字符串似乎包含无效的 char
组合。具体来说,我找到了没有跟随低代理人的高代理人。
谁能解释为什么会这样?我是否必须显式生成随机低代理来跟随高代理?我以为这不需要,因为我使用的是 Character
class.
int
变体
这是测试代码,最近 运行 产生了以下错误配对:
配对错误:d928 - d863 配对错误:da02 - 7bb6 配对错误:dbbc - d85c 配对错误:dbc6 - d85c
public static void main(String[] args) {
Random r = new Random();
StringBuilder builder = new StringBuilder();
int count = 500;
while (count > 0) {
int codePoint = r.nextInt(Character.MAX_CODE_POINT + 1);
if (!Character.isDefined(codePoint)
|| Character.getType(codePoint) == Character.PRIVATE_USE) {
continue;
}
builder.appendCodePoint(codePoint);
count--;
}
String result = builder.toString();
// Test the result
char lastChar = 0;
for (int i = 0; i < result.length(); i++) {
char c = result.charAt(i);
if (Character.isHighSurrogate(lastChar) && !Character.isLowSurrogate(c)) {
System.out.println(String.format("Bad pairing: %s - %s",
Integer.toHexString(lastChar), Integer.toHexString(c)));
}
lastChar = c;
}
}
可以随机生成高或低代理项。如果这导致低代理项,或者高代理项后面没有跟随低代理项,则结果字符串无效。解决方案是简单地排除所有代理人:
if (!Character.isDefined(codePoint)
|| (codePoint <= Character.MAX_CHAR && Character.isSurrogate((char)codePoint))
|| Character.getType(codePoint) == Character.PRIVATE_USE) {
continue;
}
或者,它应该只查看从 getType
返回的类型:
int type = Character.getType(codePoint);
if (type == Character.PRIVATE_USE ||
type == Character.SURROGATE ||
type == Character.UNASSIGNED)
continue;
(从技术上讲,您还可以允许随机生成高代理项并添加另一个随机低代理项,但这只会创建其他随机代码点 >= 0x10000,这可能又是未定义的或供私人使用。)
您需要排除所有代孕孤儿(即高代孕和低代孕)。
仅供参考,UnicodeData.txt 的下一段摘录显示了代理项的代码点间隔:
D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;; DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;; DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;; DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;