633

在c#中比较两个字符串是否相等时,InvariantCulture和Ordinal比较有什么区别?

4

9 回答 9

338

不变文化

使用一组“标准”字符顺序(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)。

于 2009-01-29T18:44:33.433 回答
324

例如,它确实很重要 - 有一种叫做字符扩展的东西

var s1 = "Strasse";
var s2 = "Straße";

s1.Equals(s2, StringComparison.Ordinal);           //false
s1.Equals(s2, StringComparison.InvariantCulture);  //true

随着InvariantCultureß 字符扩展为 ss。

于 2013-11-20T00:40:49.873 回答
137

指向在 .NET Framework 中使用字符串的最佳实践

  • 使用StringComparison.OrdinalorStringComparison.OrdinalIgnoreCase进行比较作为与文化无关的字符串匹配的安全默认值。
  • 使用比较StringComparison.OrdinalStringComparison.OrdinalIgnoreCase以获得更好的性能。
  • 根据比较在语言上不相关(例如,符号)时使用非语言StringComparison.OrdinalStringComparison.OrdinalIgnoreCase值而不是字符串操作。CultureInfo.InvariantCulture

最后:

  • StringComparison.InvariantCulture在大多数情况下不要使用基于的字符串操作。少数例外之一是当您保留具有语言意义但与文化无关的数据时。
于 2014-02-25T10:48:40.357 回答
60

另一个方便的区别(在英语中重音不常见)是 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"

于 2009-02-09T19:06:20.740 回答
35

尽管问题是关于平等的,但为了快速直观地参考,这里使用几种文化对一些字符串进行排序,说明了那里的一些特质。

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));
}
于 2014-06-10T23:39:49.960 回答
28

不变量是一种语言上合适的比较类型。
序数是一种二进制类型的比较。(更快)
http://www.siao2.com/2004/12/29/344136.aspx

于 2010-06-02T20:56:59.143 回答
7

这是一个示例,其中使用 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。

于 2015-07-11T21:22:57.947 回答
4

无需使用花哨的 unicode 字符示例来显示差异。这是我今天发现的一个简单示例,令人惊讶,它仅包含 ASCII 字符。

根据 ASCII 表,0(48, 0x30) 按顺序比较时小于_(95, 0x5F)。InvariantCulture 会说相反(下面的 PowerShell 代码):

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1
于 2017-11-29T20:09:08.430 回答
-8

始终尝试在那些接受它作为重载的字符串方法中使用 InvariantCulture。通过使用 InvariantCulture,您就安全了。许多 .NET 程序员可能不使用此功能,但如果您的软件将被不同文化使用,InvariantCulture 是一个非常方便的功能。

于 2009-02-18T14:52:55.837 回答