程序内部用的字符串,用Ordinal;展示给人看的文字,用CurrentCulture。
记住这句话,90% 的场景就不会选错。下面解释为什么。
一、为什么字符串比较有好几种?
因为"两个字符串谁排前面"有两种完全不同的标准:
- 计算机的标准:每个字符都有一个编号,按编号大小比。
- 人的标准:像查字典一样,按字母顺序比。
这两种标准经常给出相反的结果。StringComparer就是让你选择用哪种标准。
二、Ordinal:按编号比
每个字符在计算机里都有一个编号:
数字 0~9 = 48~57 大写 A~Z = 65~90 小写 a~z = 97~122 é = 233Ordinal 只看编号大小,从左往右逐个比,遇到第一个不同的字符就定胜负。
所以它的排序是:数字 → 大写字母 → 小写字母 → 带重音的字母。
例子:"a"vs"B"
- a 的编号是 97,B 的编号是 66
- 97 更大,所以
"a"排在后面
三、InvariantCulture:像查英文字典
它分三轮比较,前一轮分出胜负,就不再往下比:
- 第 1 轮:只看字母(忽略大小写和重音)
- 第 2 轮:看重音(没有重音的在前)
- 第 3 轮:看大小写(小写在前)
例子:
| 比较 | 结果 | 原因 |
|---|---|---|
"a"vs"B" | a 在前 | 第 1 轮:字典里 a 在 b 前面 |
"resume"vs"résumé" | resume 在前 | 第 1 轮打平,第 2 轮:没重音的在前 |
"apple"vs"Apple" | apple 在前 | 前两轮打平,第 3 轮:小写在前 |
四、同一对单词,两种规则结果相反
"apple"vs"Zebra":
| 规则 | 怎么比 | 谁在前 |
|---|---|---|
| Ordinal | a=97,Z=90,Z 编号更小 | Zebra |
| InvariantCulture | 字典里 a 在 z 前面 | apple |
对一组单词排序,差别更明显:
Ordinal: Apple, Zebra, apple, banana InvariantCulture: apple, Apple, banana, Zebra第二种才是人觉得"正常"的顺序。
五、既然 InvariantCulture 更像人,为什么程序里推荐 Ordinal?
因为 InvariantCulture 有三个缺点:
- 慢。它要做三轮比较,Ordinal 只比数字。
- 会"看不见"某些字符。比如软连字符这种不可见字符会被直接忽略,
"coop"和中间藏了一个不可见字符的"coop"会被判断为相等。如果用它做安全校验,可能被人绕过。 - 结果可能因系统而异。它依赖操作系统的语言库,不同版本可能有细微差别。
而程序内部的字符串(字典的键、文件名、配置项、网址)根本不需要"像人一样"排序,只需要快、准、永远不变。这正是 Ordinal 的优点。
六、Culture 是什么?
Culture(区域性)就是**“某个国家或地区的书写习惯”**,比如zh-CN(中国大陆中文)、en-US(美国英语)、de-DE(德国德语)。
它不只影响字符串比较,还影响很多东西:
| 影响什么 | 美国 en-US | 德国 de-DE |
|---|---|---|
| 数字 | 1,234.56 | 1.234,56 |
| 货币 | $1,234.56 | 1.234,56 € |
| 日期 | 10/13/2026 | 13.10.2026 |
一个常见的坑:在德国电脑上,double.Parse("1.5")得到的是15,而不是 1.5,因为德国人用点号作千位分隔符。
三种 Culture 的区别:
- CurrentCulture:跟着用户电脑的设置走。中国用户看到中国格式,德国用户看到德国格式。
- InvariantCulture:固定不变的"通用格式"(基于英语),在任何电脑上都一样。适合保存文件、写配置。
- 具体某个 Culture:比如
new CultureInfo("de-DE"),你指定用哪国规则就用哪国。
七、OrdinalIgnoreCase 是怎么忽略大小写的?
简单理解:把字母都转成大写,再按编号比。
所以"Hello"和"HELLO"相等。
需要知道的两个细节:
- 它一个字符对一个字符地转换。德语的
ß不会变成SS,所以"Straße"和"STRASSE"不相等。 - 它不受用户电脑设置影响。在土耳其语环境下,
i的大写是İ(带点),如果用CurrentCultureIgnoreCase,"file"和"FILE"会被判断为不相等。而OrdinalIgnoreCase永远判断为相等。
所以不要写a.ToUpper() == b.ToUpper(),直接用OrdinalIgnoreCase,更快也更安全。
八、怎么选?一张表搞定
| 场景 | 用哪个 |
|---|---|
| 字典的键、标识符、Linux 文件名 | Ordinal |
| HTTP 头、Windows 文件名、环境变量 | OrdinalIgnoreCase |
| 给用户看的列表排序 | CurrentCulture |
| 给用户用的搜索框 | CurrentCultureIgnoreCase |
| 需要按字典排序,但要求每台电脑结果一样 | InvariantCulture |
| 把数字、日期保存到文件或 JSON | CultureInfo.InvariantCulture(用于格式化) |
九、动手试试
新建控制台项目,把下面代码粘贴到Program.cs,运行dotnet run:
usingSystem.Globalization;string[]words={"banana","Apple","apple","Zebra"};// 1. 两种规则排序对比Console.WriteLine("Ordinal: "+string.Join(", ",words.OrderBy(w=>w,StringComparer.Ordinal)));Console.WriteLine("InvariantCulture: "+string.Join(", ",words.OrderBy(w=>w,StringComparer.InvariantCulture)));// 2. 忽略大小写的字典vardict=newDictionary<string,int>(StringComparer.OrdinalIgnoreCase){["Name"]=1};Console.WriteLine("找到 name 吗?"+dict.ContainsKey("name"));// True// 3. 土耳其语陷阱CultureInfo.CurrentCulture=newCultureInfo("tr-TR");Console.WriteLine("CurrentCultureIgnoreCase: "+StringComparer.CurrentCultureIgnoreCase.Equals("file","FILE"));// FalseConsole.WriteLine("OrdinalIgnoreCase: "+StringComparer.OrdinalIgnoreCase.Equals("file","FILE"));// True// 4. 德国格式解析陷阱Console.WriteLine("德国解析 1.5 = "+double.Parse("1.5",newCultureInfo("de-DE")));// 15总结
- Ordinal= 按编号比,快、准、永远不变,适合程序内部。
- InvariantCulture= 按字典比(字母 → 重音 → 大小写),适合需要固定结果的人类可读排序。
- CurrentCulture= 按用户所在地区的习惯比,适合展示给用户。
- Culture不只管比较,还管数字、货币、日期的格式。
- OrdinalIgnoreCase= 转大写后按编号比,忽略大小写时的首选。