关于c#:不变区域性和序数字符串比较之间的差异 InvariantCulture and Ordinal string

Difference between InvariantCulture and Ordinal string comparison

在比较C中的两个字符串是否相等时,不变文化和序数比较有什么区别?


不变文化

使用一组"标准"的字符顺序(A、B、C…)等等)。这与某些特定的区域设置不同,这些区域设置可以按不同的顺序对字符进行排序("a-with-acute"可能在"a"之前或之后,具体取决于区域设置,等等)。

依次的

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

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

1
2
3
4
5
6
7
8
9
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)

你可以看到,不变培养产生(U+0069,U+0049,U+00131),序数产生(U+0049,U+0069,U+00131)。


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

1
2
3
4
5
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的字符串操作。

最后:

  • 在大多数情况下,不要使用基于StringComparison.InvariantCulture的字符串操作。少数例外之一是当你坚持有语言意义但文化上不可知的数据。

另一个方便的区别(在英语中重音不常见)是,不变区域性比较首先按不区分大小写比较整个字符串,然后根据需要(和要求)在第一次比较后仅按大小写区分不同的字母。(当然,您也可以进行不区分大小写的比较,这是不区分大小写的。)更正:重音字母被认为是同一个字母的另一种风格,比较字符串时,首先忽略重音,然后在一般字母都匹配的情况下对其进行说明(与不同的大小写不同,但最终不会忽略)。在不区分大小写的比较中)。这组人将相同单词的重音版本放在一起,而不是在第一个重音差异处完全分开。这是通常在字典中可以找到的排序顺序,大写单词出现在它们的小写等价物旁边,重音字母靠近相应的未重音字母。

顺序比较严格地比较数字字符值,在第一个差异处停止。这种排序方式将大写字母与小写字母完全分离(重音字母可能与小写字母分离),因此大写单词的排序方式不会接近小写字母。

InvariantCulture还认为大写字母大于小写字母,而Ordinal认为大写字母小于小写字母(保留了以前计算机使用小写字母之前的ASCII,因此首先分配大写字母,因此其值低于后来添加的小写字母)。

例如,按序数:"0" <"9" <"A" <"Ab" <"Z" <"a" <"aB" <"ab" <"z" <"á" <"áb" <"á" <"áb"

按不变文化:"0" <"9" <"a" <"A" <"á" <"á" <"ab" <"aB" <"Ab" <"áb" <"áb" <"z" <"Z"


尽管这个问题是关于平等的,为了便于快速的视觉参考,这里的一些字符串的排序使用了几个文化来说明其中的一些特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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标志物

用于生成上表的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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));
}


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


下面是一个示例,其中使用InvariantCultureIgnoreCase和OrdinalIgnoreCase进行的字符串相等性比较不会得出相同的结果:

1
2
3
4
5
6
7
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字符Exmaples来显示差异。这是我今天发现的一个简单的例子,它令人惊讶,只包含ASCII字符。

根据ASCII表,当按顺序比较时,0(0x48)小于_(0x95)。InvariantCulture会说相反的话(下面是PowerShell代码):

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

始终尝试在接受它为重载的字符串方法中使用InvariantCulture。通过使用不变的区域性,您是安全的。许多.NET程序员可能不使用此功能,但如果您的软件将由不同的区域性使用,则InvariantCulture是一个非常方便的功能。