【问题标题】:Cannot identify surrogate characters in Java string无法识别 Java 字符串中的代理字符
【发布时间】:2017-12-31 03:25:46
【问题描述】:

我无法识别 devā́n 等字符串中的代理字符。我在 SO 上阅读了有关该主题的相关问题,但这仍然有问题...
如您所见,这个字符串的“自然”长度(我刚刚组成了那个表达式)是 5,但 "devā́n".length() 给了我 6。
这很好,因为ā́ 在内部由两个字符组成(它不属于 UTF-16 代码范围)。但我想得到字符串的长度,就像你阅读它或打印它一样,所以在这种情况下是5

我尝试使用 herehere 找到的以下技巧来识别怪异字符,但它不起作用,我总是得到 6 个。看看这个:

//string containing surrogate pair
String s = "devā́n";

//prints the string properly
System.out.println("String: " + s);

//prints "Length: 6"
System.out.println("Length: " + s.length());

//prints "Codepoints: 6"
System.out.println("Codepoints: " + s.codePointCount(0, s.length()));

//false
System.out.println(
        Character.isSurrogate(s.charAt(3)));

//false
System.out.println(
        Character.isSurrogate(s.charAt(4)));

//six code points
System.out.println("\n");
for (int i = 0; i < s.length(); i++) {
    System.out.println(s.charAt(i) + ": " + s.codePointAt(i));
}

ā́ 是否可能不是一对有效的代理字符?如何识别这样的复合字符并将其仅算作一个?

顺便说一句,上面代码的输出是

String: devā́n
Length: 6
Codepoints: 6
false
false


d: 100
e: 101
v: 118
ā: 257
́: 769
n: 110

【问题讨论】:

    标签: java string character-encoding


    【解决方案1】:

    首先,769 (U+0301) 不作为代理字符进行测试的原因是它不是代理字符。当 Unicode 代码点位于平面 0 之外时,使用 UTF-16 表示的代理字符。 (代理是 U+D800 到 U+DFFF 范围内的代码单元。)

    因此,您在这里真正要做的是弄清楚 UTF-16 字符串中有多少个“普通”字符。这分两步完成:

    • 首先,使用Normalizer API 将字符串规范化为NFC 形式(请参阅Normalizing Text)。
    • 然后使用String API 查找code point中的数量 字符串;例如使用String.codePointCount (javadoc)。

    在这种情况下,这仍然失败。原因是码位序列

    ā: 257
    ́: 769
    

    实际上表示一个带有两个变音符号的“a”字符。这不能表示为单个 Unicode 代码点,因此它的 NFC 是两个代码点。

    更令人困惑的是,典型的渲染器会在后面的字符上显示“尖锐”重音。所以它看起来在你的例子中你有一个“n急性”。

    要处理像这样的病态示例将非常困难,其中基本字符具有多个变音符号,可能会出现奇怪的呈现。也许您需要翻译成 NFD,然后计算不是变音符号的代码点。

    【讨论】:

    • 谢谢,这听起来合乎逻辑。但是s = Normalizer.normalize(s, Form.NFC);System.out.println(s.codePointCount(0, s.length())); 仍然给我6。我做错了什么?
    • 谢谢!我用s = Normalizer.normalize(s, Form.NFD);s = s.replaceAll("\\W",""); 对此进行了测试,现在它的长度确实是5。
    猜你喜欢
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2013-11-30
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多