You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中对连字字符折叠/归一化以实现字符串比较

字符串比较中的连字字符处理问题

问题背景

我最近在深挖字符串比较里的冷门细节,快陷进去了!想实现包含连字字符的字符串和规范非连字版本的等价比较——比如法语学习应用里,用户输入oeuf或œuf都能被识别为同一个词。我觉得这叫“折叠”,但不确定对不对。

我试过用NFKD归一化字符串,以为能把字符拆成组成部分,但只有部分Unicode码位支持分解,比如示例里的‘œ’就不行,这可把我难住了。

示例代码

using System.Text;
using System.Globalization;

// 该字符不支持分解
string str1 = "\u0153"; // œ (LATIN SMALL LIGATURE OE)
string str2 = "oe";
string str1norm = str1.Normalize(NormalizationForm.FormKD);

Console.WriteLine(str1norm.IsNormalized()); // True
Console.WriteLine(str1norm.Equals(str2));   // False
Console.WriteLine(str1norm.Length);         // 1

// 该字符支持分解
str1 = "\uFB06"; // st (LATIN SMALL LIGATURE ST)
str2 = "st";
str1norm = str1.Normalize(NormalizationForm.FormKD);

Console.WriteLine(str1norm.IsNormalized()); // True
Console.WriteLine(str1norm.Equals(str2));   // True
// (未归一化比较)在大多数区域设置中为True,但并非全部(见下文)
Console.WriteLine(str1.Equals(str2, StringComparison.CurrentCultureIgnoreCase)); 
Console.WriteLine(str1norm.Length);         // 2

核心问题

既然只有部分连字可分解,我有三个问题:

  • 不用手动遍历所有Unicode码位,怎么判断一个字符是否可分解?
  • 有没有办法不用手动维护“不可分解字符-扩展形式”字典,就能实现字符串和规范版本的比较?我可不想挨个敲这些映射关系。
  • (额外问题)为什么有的多字符连字(比如示例里的‘st’连字)能分解,有的却不行?像‘œ’这类字符特殊在哪?

补充研究

编辑: 我查了更多资料,像‘œ’或德语‘ß’这类字符被视为独立字符,而非组合字符。它们代表当前语言中的实际使用形式,哪怕历史上是由其他形式演变而来的。Unicode是基于当前使用情况定义的,所以把它们标记为不可分解是合理的。

区域设置的诡异现象

我统计了自己电脑上的区域设置情况:‘st’不用归一化就等于‘st’的有862个,只有7个区域设置会比较失败,分别是:

  • aa(阿法尔语)
  • aa-DJ(阿法尔语-吉布提)
  • aa-ER(阿法尔语-厄立特里亚)
  • aa-ET(阿法尔语-埃塞俄比亚)
  • en-US-POSIX(美式英语POSIX设置)
  • ssy(萨霍语)
  • ssy-ER(萨霍语-厄立特里亚)

这事挺有意思,但这种差异实在让人摸不着头脑。我知道阿法尔语和萨霍语用的是拉丁字母书写系统,可能它们的Unicode代码页不太常用,缺了其他区域设置里有的连字映射条目。

Invariant文化的奇怪行为

最后还有个困惑:单字符‘st’和它的分解形式‘st’在.NET的Invariant文化下,只有忽略大小写时才相等,但明明两个字符串都是小写的:

//...接之前的代码...
Console.WriteLine(str1.Equals(str2, StringComparison.InvariantCulture));           // False
Console.WriteLine(str1.Equals(str2, StringComparison.InvariantCultureIgnoreCase)); // True

我知道有人会说“归一化之后就别纠结了”,但我就是想搞清楚这到底是为什么。


内容的提问来源于stack exchange,提问作者Dave R.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 19:33:11