gpt4 book ai didi

c# - 将(一些)Unicode 非间距标记与相关字母组合以进行统一处理

转载 作者:行者123 更新时间:2023-12-01 23:32:37 24 4
gpt4 key购买 nike

我正在用 C# 编写文本处理 Windows 应用程序。该应用程序处理许多纯文本文件以计算字符、单词等。为此,该应用程序遍历每个文件中的字符。我发现一些文本文件使用 Unicode 字符 U+00E1(带尖音符的小写字母 A)表示重音字母,例如 á,而其他文本文件使用简单的无重音符号 a( U+0061,小写字母 A) 后跟 U+0301(组合尖音符)。记事本或我用过的其他编辑器在屏幕上呈现文本的方式没有视觉差异,但底层字符流明显不同。

我想以同样的方式检测和处理这两种情况。换句话说,我希望我的应用程序将一个字母后跟一个组合代码点组合成等效的独立字符。例如,我想将序列 U+0061 U+0301 组合成 U+00E1。据我所知,除了针对纯字母和组合字符的所有可能组合的大型且容易出错的查找表之外,没有简单的算法可以执行此操作。

是否有更简单、更直接的算法来执行此组合?

最佳答案

你指的是 Unicode normalization forms .该页面介绍了一些有趣的细节,但要点是代表例如重音字母作为单个代码点(例如 á 作为 U+00E1)是规范化形式 C 或 NFC,作为单独的代码点(例如 á 作为 U+0061 U+0301 ) 是 NFD。

Unicode specification 的第 3.11 节进入有关如何实现它的血淋淋的细节,以及一些额外的细节 here .

幸运的是,您不需要自己实现:string.Normalize()已经存在。

"\u00E1".Normalize(NormalizationForm.FormD); // \u0061\u0301
"\u0061\u0301".Normalize(NormalizationForm.FormC); // \u00E1

也就是说,我们只是触及了“角色”是什么的皮毛。一个很好的例子是使用表情符号,但它也适用于各种脚本:有现代脚本,其中普通字符由两个代码点组成,并且没有可用的单个组合代码点。这会弹出例如泰米尔语和泰语,以及一些东欧语言 (IIRC)。

我最喜欢的例子是👩🏽‍🚒,或“女消防员:中等肤色”。想猜猜它是如何编码的吗?没错,4 个不同的代码点:U+1F469 U+1F3FD U+200D U+1F692。

  • U+1F469 是 👩,女人表情符号。
  • U+1F3FD 是“Emoji Modifier Fitzpatrick Type-4”,它将之前的表情符号修改为棕色肤色👩🏽,单独出现时呈现为🏽。
  • U+200D 是一个“零宽度连接器”,用于将代码点粘合在一起成为同一个字符
  • U+1F692 是 🚒,消防车表情符号。

所以你给一个女人加上棕色肤色,把她粘在消防车上,你就会得到一个棕色皮肤的女消防员。

(只是为了好玩,尝试将👩🏽‍🚒粘贴到各种编辑器中,然后在其上使用退格键。如果它正确呈现,一些编辑器将其变成👩🏽然后👩然后删除它,而其他人则跳过各个部分。但是,您选择它作为单个字符。这反射(reflect)了在某些脚本中编辑复杂字符的工作方式)。

(另一个有趣的金 block 是国旗表情符号。Unicode 定义了“区域指示符号字母 A-Z”(U+1F1E6 到 U+1F1FF),并且国旗被编码为国家的 ISO 3166-1 alpha-2 字母国家代码,使用这些指标符号。所以 🇺🇸 是 🇺 后跟 🇸。将 🇸 粘贴在 🇺 之后,就会出现一个标志!)

当然,如果您逐个代码点迭代此代码点,您将单独访问 U+1F469 U+1F3FD U+200D U+1F692,这可能不是您想要的。

如果你逐个字符地迭代这个,你会因为 surrogate pairs 而做得更糟: 像 U+1F469 这样的代码点太大了,无法使用一个 16 位字符来表示,所以我们需要使用其中两个。这意味着如果您尝试遍历 U+1F469,您实际上会发现您有两个字符:0xD83D(高代理项)和 0xDC69(低代理项)。

相反,我们需要引入extended grapheme clusters ,代表您传统上认为的单个字符。如果您想自己做这件事,又会很复杂,而且有人会再次为您提供帮助:StringInfo.GetTextElementEnumerator .请注意,这是 .NET 5 之前的问题,并且 didn't properly handle all EGCs .

然而,在 .NET 5 中:

// Number of chars, as 3 of the codepoints need to use surrogate pairs when
// encoded with UTF-16
"👩🏽‍🚒".Length; // 7

// Number of Unicode codepoints
"👩🏽‍🚒".EnumerateRunes().Count(); // 4

// Number of extended grapheme clusters
GetTextElements("👩🏽‍🚒").Count(); // 1

public static IEnumerable<string> GetTextElements(string s)
{
TextElementEnumerator charEnum = StringInfo.GetTextElementEnumerator(s);
while (charEnum.MoveNext())
{
yield return charEnum.GetTextElement();
}
}

我在这里使用表情符号作为一个可以理解的例子,但这些问题也会出现在现代脚本中,使用文本的人需要意识到这些问题。

关于c# - 将(一些)Unicode 非间距标记与相关字母组合以进行统一处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66062139/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com