哪个组件处理字符串中的组合分音符?
What component handles a Combining Diaeresis in a string?
我正在处理 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, which is a "Combining Diaeresis". This is a so called combining mark that belongs to the graphemes, or more precisely to the combining diacritics。所以这一切都是有道理的,但我不明白是什么软件组件将两个字符组合成一个变音符号,以及在哪里指定了这种行为。
- 这与功能强大的字符代码表使用几个字节作为内部表示无关。几个字节不等于两个组合字符。
- 字符串的任何简单
print()
都会显示组合字符,因此它既不是上面的某些 UI 层。
- 我记得在 PHP 中也观察到了这一点。我想任何现代语言都可以处理这个问题。
什么因素导致组合字符显示为单个组合字符?这一切有多可靠?
是否有 Java 一种规范化方法,使组合代码点成为单个代码点,例如 here?对使用 Regex 有帮助...
非常感谢任何提示。
答案一:规范与责任
您描述的行为在 Unicode Standard Annex #15, Unicode Normalization Forms 中定义。这是关于组合字符和单个代码点的等效性以及代码点的分解。德语以外的许多语言严重依赖组合字素。
Java 在内部将字符串表示为 UTF-16。因此,它使用 String
class 所做的一切都是将 UTF-16 代码链传递给其他组件。正确组合链取决于周围的软件(例如任何类型的文本视图组件)。你会在某些时刻感受到这一点,例如正则表达式将组合 ö
分开,但它在某些视图中显示正确。
顺便说一句,如果你用 Combining Diaeresis 做一些实验,请注意还有一个 "non-functional" 代码 168,这是一个简单的 ASCII 字符,称为 "Spacing Diaeresis"。 Code 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
...
我正在处理 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, which is a "Combining Diaeresis". This is a so called combining mark that belongs to the graphemes, or more precisely to the combining diacritics。所以这一切都是有道理的,但我不明白是什么软件组件将两个字符组合成一个变音符号,以及在哪里指定了这种行为。
- 这与功能强大的字符代码表使用几个字节作为内部表示无关。几个字节不等于两个组合字符。
- 字符串的任何简单
print()
都会显示组合字符,因此它既不是上面的某些 UI 层。 - 我记得在 PHP 中也观察到了这一点。我想任何现代语言都可以处理这个问题。
什么因素导致组合字符显示为单个组合字符?这一切有多可靠?
是否有 Java 一种规范化方法,使组合代码点成为单个代码点,例如 here?对使用 Regex 有帮助...
非常感谢任何提示。
答案一:规范与责任
您描述的行为在 Unicode Standard Annex #15, Unicode Normalization Forms 中定义。这是关于组合字符和单个代码点的等效性以及代码点的分解。德语以外的许多语言严重依赖组合字素。
Java 在内部将字符串表示为 UTF-16。因此,它使用 String
class 所做的一切都是将 UTF-16 代码链传递给其他组件。正确组合链取决于周围的软件(例如任何类型的文本视图组件)。你会在某些时刻感受到这一点,例如正则表达式将组合 ö
分开,但它在某些视图中显示正确。
顺便说一句,如果你用 Combining Diaeresis 做一些实验,请注意还有一个 "non-functional" 代码 168,这是一个简单的 ASCII 字符,称为 "Spacing Diaeresis"。 Code 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
...