StringComparer.CurrentCulture/InvariantCulture为何默认不区分大小写?
StringComparer 大小写敏感性问题解析与控制方案
你观察到的现象是因为文化相关的字符串比较(CurrentCulture/InvariantCulture)默认遵循对应文化的排序规则,很多文化(包括不变文化)的排序规则里,大小写字母的排序权重是相同的,所以哪怕没用到IgnoreCase版本,也会出现不区分大小写的比较结果;而Ordinal比较是直接基于字符的Unicode码点,严格区分大小写,这才符合你对大小写敏感比较的预期。
为什么会出现这种差异?
- 文化比较的规则特性:
StringComparer.CurrentCulture和InvariantCulture的逻辑依赖.NET内置的文化排序表,不少文化里大小写字母被视为排序等价(权重一致),所以非IgnoreCase模式下,也可能出现"A"和"a"甚至"A"与"b"相关比较结果一致的情况——这不是bug,是文化排序规则的设计。 - Ordinal比较的本质:
StringComparer.Ordinal直接比对字符的Unicode标量值,比如'A'是U+0041,'a'是U+0061,'b'是U+0062,所以会严格区分大小写和不同字母,完全是字面意义上的字符匹配。
怎么控制文化相关比较的大小写敏感性?
要让文化相关的比较严格区分大小写,不能直接用StringComparer的静态属性,得用指定排序选项的文化比较器,具体有两种方式:
- 创建带排序选项的文化比较器
通过CultureInfo的CompareInfo,调用GetStringComparer并传入CompareOptions.None(明确不忽略大小写),就能得到严格区分大小写的文化比较器:
// 当前文化下的严格区分大小写比较器 var currentCaseSensitive = CultureInfo.CurrentCulture.CompareInfo.GetStringComparer(CompareOptions.None); // 不变文化下的严格区分大小写比较器 var invariantCaseSensitive = CultureInfo.InvariantCulture.CompareInfo.GetStringComparer(CompareOptions.None);
用这个比较器做"A"和"a"、"A"和"b"的比较,就能得到区分大小写的结果。
- 在string.Compare中指定CompareOptions
如果直接用string.Compare方法,也可以传入CompareOptions.None强制区分大小写:
// 当前文化下严格区分大小写比较 int compareResult = string.Compare("A", "a", CultureInfo.CurrentCulture, CompareOptions.None); // 结果不为0,说明大小写被区分开了
额外提醒
如果你要的是完全基于字符码点的严格匹配,优先用StringComparer.Ordinal或StringComparer.OrdinalIgnoreCase,这俩性能最高,行为完全可预测,不受任何文化规则影响;文化相关的比较器只适合需要遵循特定地区排序习惯的场景,比如按当地语言规则排序字符串,不需要文化适配的话,Ordinal比较是更靠谱的选择。
内容的提问来源于stack exchange,提问作者RoadieRich
相关产品推荐
相关产品推荐

