将代码点与Java角色进行比较的“正确”方法是什么?例如:
int codepoint = String.codePointAt(0);
char token = '\n';
我知道我可能会这样做:
if (codepoint==(int) token)
{ ... }
但这段代码看起来很脆弱。是否有正式的API方法可用于将codepoints
与chars
进行比较,或将char
转换为codepoint
进行比较?
答案 0 :(得分:43)
一点背景:当Java出现在1995年时,char
类型基于原始的“Unicode 88”规范,该规范限制为16位。一年后,当实施Unicode 2.0时,引入了代理字符的概念超出了16位的限制。
Java内部代表UTF-16格式的所有String
。对于超过U + FFFF的代码点,代码点由代理对表示,即两个char
s,第一个是高代理代码单元,(在范围内\ uD800- \ uDBFF),第二个作为低代理代码单元(在\ uDC00- \ uDFFF范围内)。
从早期开始,所有基本的Character
方法都基于一个代码点可以用char
表示的假设,这就是方法签名的样子。我想保留当Unicode 2.0出现时没有改变的向后兼容性,并且在处理它们时需要谨慎。引用Java documentation:
将char
投射到int
,就像在示例中一样,但工作正常。
答案 1 :(得分:10)
Character类包含许多用于处理Unicode代码点的有用方法。注意像Character.toChars(int)这样的方法返回一组字符。如果您的代码点位于补充范围内,那么该数组的长度将为两个字符。
您希望如何比较这些值取决于您是否要支持所有Unicode值。此示例代码可用于迭代String的代码点,测试是否匹配补充字符MATHEMATICAL_FRAKTUR_CAPITAL_G(? - U + 1D50A):
public final class CodePointIterator {
private final String sequence;
private int index = 0;
public CodePointIterator(String sequence) {
this.sequence = sequence;
}
public boolean hasNext() {
return index < sequence.length();
}
public int next() {
int codePoint = sequence.codePointAt(index);
index += Character.charCount(codePoint);
return codePoint;
}
public static void main(String[] args) {
String sample = "A" + "\uD835\uDD0A" + "B" + "C";
int match = 0x1D50A;
CodePointIterator pointIterator = new CodePointIterator(sample);
while (pointIterator.hasNext()) {
System.out.println(match == pointIterator.next());
}
}
}
对于Java 8及以上版本CharSequence.codePoints()可以使用:
public static void main(String[] args) {
String sample = "A" + "\uD835\uDD0A" + "B" + "C";
int match = 0x1D50A;
sample.codePoints()
.forEach(cp -> System.out.println(cp == match));
}
我创建了一个table来帮助处理有时需要处理的Unicode字符串长度和比较情况。
答案 2 :(得分:3)
对于可以用单个char(16位,基本多语言平面)表示的字符,只需将char转换为整数(如问题所示)就可以得到代码点,因此不需要特殊的执行转换的方法。
如果您要将char与代码点进行比较,则不需要任何特殊的外壳。只需将char与int直接比较(如问题所示)。如果int表示基本多语言平面之外的代码点,则结果将始终为false。
答案 3 :(得分:2)
对于基本多语言平面中的字符,将char转换为int将获得代码点。这对应于可以在单个16位char值中编码的所有unicode值。此平面外的值(代码点超过0xffff)不能表示为单个字符。这可能就是没有Character.toCodePoint(char值)的原因。
答案 4 :(得分:0)
Java使用16位(UTF-16)模型来处理字符,因此任何带有代码点&gt;的字符都是如此。 0xFFFF作为16位字符的对存储在字符串中,使用两个surrogate字符来表示平面内的平面和字符。
如果要根据完整的Unicode标准正确处理字符和字符串,则需要处理考虑到这一点的字符串。
XML非常关心这一点;对于与字符相关的代码,访问Xerces中的XMLChar类(Java版本5.0及更高版本)非常有用。
查看Saxon XSLT / XQuery处理器也很有启发性,因为它是一个表现良好的XML应用程序,它必须考虑Java如何在字符串中存储代码点。 XQuery 1.0和XPath 2.0具有codepoints-to-string和string-to-codepoints的功能;获得撒克逊的副本并与他们一起玩,看看它们是如何工作的可能是有益的。