不变文化和序数字符串比较的区别

当在c#中比较两个相等的字符串时,不变文化和序数比较之间有什么区别?

173968 次浏览

InvariantCulture

使用“标准”字符顺序集(a,b,c,…)等等)。这与一些特定的语言环境形成对比,这些语言环境可能会以不同的顺序对字符进行排序('a-with-acute'可能在'a'之后< em >或< / em >之前,这取决于语言环境,等等)。

序数

另一方面,它只查看代表字符的原始字节的值。


http://msdn.microsoft.com/en-us/library/e6883c06.aspx上有一个很好的示例,它显示了各种stringcompare值的结果。在最后,它显示(节选):

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),序数产生(U+0049, U+0069, U+00131)。

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

总是尝试在那些接受它作为重载的字符串方法中使用InvariantCulture。通过使用InvariantCulture,你是安全的。许多。net程序员可能不会使用这个功能,但如果您的软件将被不同的区域性使用,那么InvariantCulture是一个非常方便的特性。

不变量是一种语言上合适的比较类型 序数是一种二进制类型的比较。(快)
看到# EYZ0 < / p >

这确实很重要,比如——有一种东西叫做角色扩展

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


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

对于InvariantCulture, ß字符扩展为ss。

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

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

最后:

  • # EYZ1。少数例外之一是当您坚持使用语言上有意义但文化上不可知的数据时。

虽然这个问题是关于平等的,但是为了快速的可视化参考,这里使用了一些区域性说明了一些特性的一些字符串排序的顺序。

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-DEja-JPen-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));
}

下面是一个例子,使用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将为假,而equals2将为真。

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

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

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1