C# 的 StringInfo 和 TextElementEnumerator 无法正确识别字形

C#'s StringInfo and TextElementEnumerator can't recognize graphemes properly

在 C# 中 StringInfoTextElementEnumerator 类 为文本元素提供方法和属性。 而here,我们可以找到文本元素的定义。

The .NET Framework defines a text element as a unit of text that is displayed as a single character, that is, a grapheme. A text element can be any of the following:

是的,它说文本元素是 .NET 中的字素。我自己也测试了一些 unicode 字符,在我测试了一个韩文字母 ''.

之前,它看起来确实是真的

众所周知,一些 Unicode 字符由多个代码点组成。此外,我们可能会遇到代码点序列,这就是我使用 StringInfoTextElementEnumerator 而不是简单的 String.

的原因

StringInfoTextElementEnumerator 可以判断 Char 是否是正确的代理对。而“\u0061\u0308”,一个由多个代码点组成的 Unicode 字符,正如预期的那样被识别为一个文本元素。但至于“\u1100\u1161”,它并没有说它也是一个文本元素。

“\u1100”是首字母“ㄱ”,“\u1161”是元音字母“ㅏ”。它们可以是单独的字符,就像我在这里写的那样显示给用户,你现在可以看到它们。但如果它们一起使用,它们将被渲染为一个字符“가”而不是“ㄱㅏ”。

韩文“가”的表示方法有两种:

  1. 使用 Hangul Syllable.
  2. 中的单个代码点 U+AC00
  3. 使用来自 Jamo 的两个代码点 U+1100U+1161

大多数情况下使用前者。后者很少用到,老实说,我根本无法想象它什么时候被用到。。 无论如何,第一个只是一个预组合字母,第二个是 LeadVowel 的序列,被视为一个字符。渲染时它们看起来完全一样,实际上两者在规范上是等价的。 此外,C# 中的以下行 returns 为真:

"\u1100\u1161".Normalize() == "\uAC00"

我想知道为什么 Normalize() 在 C# 认为它们不是一个完整的文本元素时在这里工作得很好.. 我认为这与我的 .NET 版本有关,但事实并非如此。即使在 Mono 中也会发生这种情况。

我也用 ICU 测试了它,它可以将“\u1100\u1161”视为一个字素正确! 我最初认为 StringInfoTextElementEnumerator 可以在一些简单的情况下消除对 ICU4C 的需求,所以我现在很失望..

这是我的问题:

我是不是做错了什么?

与 ICU 不同,.NET 中的文本元素不是用户感知的字符?

这里的基本问题是,根据韩国标准 KS X 1026,两个 jamos 不同于它们的组合形式 。事实上,官方标准中使用了这个确切的示例(请参阅第 6.2 节)。

长话短说,Microsoft 试图遵循该标准,但其他操作系统和应用程序不一定这样做。因此,您可以从其他软件/平台获取 "malformed" 内容,这些内容似乎在 Windows / 在 .NET 中被错误解析,即使它在这些平台上被解析 "correctly" 也是如此。

您首先需要确保您的数据格式正确(不太可能,因为 事实上的 标准是完全忽略 官方标准)或者你需要使用ICU(或类似的库)来处理这些情况。