什么组件在字符串中处理组合Diaeresis?

时间:2015-11-04 10:34:16

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

我正在使用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吗?对使用正则表达式有帮助...

非常感谢任何暗示。

1 个答案:

答案 0 :(得分:6)

答案1:规范和责任

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

Java内部将字符串表示为UTF-16。因此,它的String类所做的就是将UTF-16代码链提供给其他组件。由周围的软件(例如任何类型的文本视图组件)来正确地组合链。你感觉到这一点,例如正则表达式将您的合并ö分开,但在某些视图中显示正确。

顺便说一句,如果你使用Combining Diaeresis进行一些实验,请注意还有一个非功能性的"代码168,这是一个简单的ASCII字符,称为" Spacing Diaeresis"。代码168不会导致任何软件将两个代码点合并为一个。为此,您需要Unicode 776。

答案2:Javas规范化方法

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

在您的语言中查找unicode规范化方法,因为它们会让您摆脱单个replace()语句,并且它们包含大量经验。

Java有一个Normalizer对象,用于处理组合字符的不同表示:

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
...