在c#中比较两个字符串是否相等时,InvariantCulture和Ordinal比较有什么区别?
9 回答
不变文化
使用一组“标准”字符顺序(a、b、c、...等)。这与某些特定的语言环境形成对比,后者可能以不同的顺序对字符进行排序(“a-with-acute”可能在“a”之前或之后,具体取决于语言环境,等等)。
序数
另一方面,纯粹查看代表字符的原始字节的值。
http://msdn.microsoft.com/en-us/library/e6883c06.aspx上有一个很好的示例,它显示了各种 StringComparison 值的结果。一直到最后,它显示(摘录):
StringComparison.InvariantCulture:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is less than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)
StringComparison.Ordinal:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is greater than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)
你可以看到 InvariantCulture 产生 (U+0069, U+0049, U+00131),Ordinal 产生 (U+0049, U+0069, U+00131)。
例如,它确实很重要 - 有一种叫做字符扩展的东西
var s1 = "Strasse";
var s2 = "Straße";
s1.Equals(s2, StringComparison.Ordinal); //false
s1.Equals(s2, StringComparison.InvariantCulture); //true
随着InvariantCulture
ß 字符扩展为 ss。
指向在 .NET Framework 中使用字符串的最佳实践:
- 使用
StringComparison.Ordinal
orStringComparison.OrdinalIgnoreCase
进行比较作为与文化无关的字符串匹配的安全默认值。 - 使用比较
StringComparison.Ordinal
或StringComparison.OrdinalIgnoreCase
以获得更好的性能。 - 根据比较在语言上不相关(例如,符号)时使用非语言
StringComparison.Ordinal
或StringComparison.OrdinalIgnoreCase
值而不是字符串操作。CultureInfo.InvariantCulture
最后:
StringComparison.InvariantCulture
在大多数情况下不要使用基于的字符串操作。少数例外之一是当您保留具有语言意义但与文化无关的数据时。
另一个方便的区别(在英语中重音不常见)是 InvariantCulture 比较首先按不区分大小写的方式比较整个字符串,然后如果有必要(并且要求)在首先比较不同的字母后按大小写进行区分。(当然,您也可以进行不区分大小写的比较,这不会区分大小写。) 更正:重音字母被认为是相同字母的另一种风格,首先比较字符串,忽略重音符号,然后在通用字母全部匹配时考虑它们(很像不同的大小写,除非在不区分大小写的比较中最终被忽略)。这将其他相同单词的重音版本组合在一起,而不是在第一个重音差异处完全分开。这是您通常会在字典中找到的排序顺序,大写的单词紧挨着它们的小写字母,重音字母靠近相应的非重音字母。
序数比较严格比较数字字符值,在第一个差异处停止。这将大写字母与小写字母完全分开(并且重音字母可能与这些字母分开),因此大写单词的排序与它们的小写等价词相去甚远。
InvariantCulture 还认为大写字母大于小写字母,而 Ordinal 认为大写字母小于小写字母(在计算机使用小写字母之前的旧时代 ASCII 的保留,大写字母首先分配,因此其值低于小写字母稍后添加)。
例如,按序数:"0" < "9" < "A" < "Ab" < "Z" < "a" < "aB" < "ab" < "z" < "Á" < "Áb" < "á" < "áb"
通过 InvariantCulture:"0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"
尽管问题是关于平等的,但为了快速直观地参考,这里使用几种文化对一些字符串进行排序,说明了那里的一些特质。
Ordinal 0 9 A Ab a aB aa ab ss Ä Äb ß ä äb ぁ あ ァ ア 亜 A
IgnoreCase 0 9 a A aa ab Ab aB ss ä Ä äb Äb ß ぁ あ ァ ア 亜 A
--------------------------------------------------------------------
InvariantCulture 0 9 a A A ä Ä aa ab aB Ab äb Äb ss ß ァ ぁ ア あ 亜
IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ß ss ァ ぁ ア あ 亜
--------------------------------------------------------------------
da-DK 0 9 a A A ab aB Ab ss ß ä Ä äb Äb aa ァ ぁ ア あ 亜
IgnoreCase 0 9 A a A Ab aB ab ß ss Ä ä Äb äb aa ァ ぁ ア あ 亜
--------------------------------------------------------------------
de-DE 0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜
IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜
--------------------------------------------------------------------
en-US 0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜
IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜
--------------------------------------------------------------------
ja-JP 0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜
IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜
观察:
de-DE
,ja-JP
, 并en-US
以相同的方式排序Invariant
仅与上述三种文化ss
不同ß
da-DK
排序完全不同IgnoreCase
旗帜对所有采样文化都很重要
用于生成上表的代码:
var l = new List<string>
{ "0", "9", "A", "Ab", "a", "aB", "aa", "ab", "ss", "ß",
"Ä", "Äb", "ä", "äb", "あ", "ぁ", "ア", "ァ", "A", "亜" };
foreach (var comparer in new[]
{
StringComparer.Ordinal,
StringComparer.OrdinalIgnoreCase,
StringComparer.InvariantCulture,
StringComparer.InvariantCultureIgnoreCase,
StringComparer.Create(new CultureInfo("da-DK"), false),
StringComparer.Create(new CultureInfo("da-DK"), true),
StringComparer.Create(new CultureInfo("de-DE"), false),
StringComparer.Create(new CultureInfo("de-DE"), true),
StringComparer.Create(new CultureInfo("en-US"), false),
StringComparer.Create(new CultureInfo("en-US"), true),
StringComparer.Create(new CultureInfo("ja-JP"), false),
StringComparer.Create(new CultureInfo("ja-JP"), true),
})
{
l.Sort(comparer);
Console.WriteLine(string.Join(" ", l));
}
不变量是一种语言上合适的比较类型。
序数是一种二进制类型的比较。(更快)
见http://www.siao2.com/2004/12/29/344136.aspx
这是一个示例,其中使用 InvariantCultureIgnoreCase 和 OrdinalIgnoreCase 进行字符串相等性比较不会给出相同的结果:
string str = "\xC4"; //A with umlaut, Ä
string A = str.Normalize(NormalizationForm.FormC);
//Length is 1, this will contain the single A with umlaut character (Ä)
string B = str.Normalize(NormalizationForm.FormD);
//Length is 2, this will contain an uppercase A followed by an umlaut combining character
bool equals1 = A.Equals(B, StringComparison.OrdinalIgnoreCase);
bool equals2 = A.Equals(B, StringComparison.InvariantCultureIgnoreCase);
如果你运行它,equals1 将为 false,equals2 将为 true。
无需使用花哨的 unicode 字符示例来显示差异。这是我今天发现的一个简单示例,令人惊讶,它仅包含 ASCII 字符。
根据 ASCII 表,0
(48, 0x30) 按顺序比较时小于_
(95, 0x5F)。InvariantCulture 会说相反(下面的 PowerShell 代码):
PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1
始终尝试在那些接受它作为重载的字符串方法中使用 InvariantCulture。通过使用 InvariantCulture,您就安全了。许多 .NET 程序员可能不使用此功能,但如果您的软件将被不同文化使用,InvariantCulture 是一个非常方便的功能。