【问题标题】:What component handles a Combining Diaeresis in a string?哪个组件处理字符串中的组合分音器?
【发布时间】:2015-11-04 10:34:16
【问题描述】:

我正在处理 Java 中的文件名列表。

我观察到文件名中的一些单个字符,例如 a、ö 和 ü 实际上由一个序列组成,您可以将其描述为两个单个 ASCII 字符:

öo¨表示

我通过codePointAt() 的检查看到了这一点。德国名字“Rölli”实际上是“Ro¨lli”:

...
20: R, 82
21: o, 111
22: ̈, 776
23: l, 108
24: l, 108
25: i, 105
...

上面日志中的字符¨value 776,这是一个“组合分音”。这是一个所谓的组合标记,属于graphemes,或者更准确地说属于combining diacritics。所以这一切都说得通,但我不明白是什么软件组件将这两个字符组合成一个变音符号,以及在哪里指定了这种行为。

  • 这与强大的字符代码表使用多个字节作为内部表示这一事实无关。几个字节与两个组合字符不同。
  • 字符串的任何简单print() 都会显示组合字符,因此它既不是上面的某个UI 层。
  • 我记得在 PHP 中也观察到了这一点。我想任何现代语言都可以处理这个问题。

什么组件导致组合字符显示为单个组合字符?这一切有多可靠?

Java 是否有一种规范化方法,可以将单个代码点变成组合代码点,例如 here?对使用正则表达式会有帮助...

非常感谢任何提示。

【问题讨论】:

    标签: java string character-encoding unicode-normalization combining-marks


    【解决方案1】:

    答案一:规范与责任

    您描述的行为在Unicode Standard Annex #15, Unicode Normalization Forms 中定义。这是关于组合字符和单个代码点的等效性以及代码点的分解。除德语以外的许多语言都严重依赖于组成字素。

    Java 在内部将字符串表示为 UTF-16。因此,它对String 类所做的只是将 UTF-16 代码链传递给其他组件。正确组合链取决于周围的软件(例如任何类型的文本视图组件)。你会在某些时刻感受到这一点,例如正则表达式将您组合的 ö 分开,但它在某些视图中正确显示。

    顺便说一句,如果你对组合分音进行一些实验,请注意还有一个“非功能性”代码 168,它是一个简单的 ASCII 字符,称为“间距分音”。 Code 168 不会导致任何软件将两个代码点合二为一。为此,您需要 Unicode 776。

    答案2:Javas规范化方法

    基本上,您应该始终考虑组合字符 - 除非您确定您的数据源无法传递它们。首先清理字符串是个好主意。

    在您的语言中寻找 unicode 规范化方法,因为它们可以让您摆脱对单个 replace() 语句的摆弄,并且它们包含很多经验。

    Java 有一个Normalizerobject 处理组合字符的不同表示:

    https://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.html

    及其教程:https://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html

    所以在调用这行代码之后:

    String normalized = Normalizer.normalize(someFileName, Normalizer.Form.NFC);
    

    上述问题的日志打印如下:

    ...
    19:  , 32
    20: R, 82
    21: ö, 246   <<< here were two combined chars before normalize()
    22: l, 108
    23: l, 108
    24: i, 105
    ...
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 2021-12-28
    • 2018-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多