InvariantCultureと序数文字列の比較の違い


548

c#で2つの文字列を比較して等しいかどうかを調べる場合、InvariantCultureと序数比較の違いは何ですか?



2
String1.Equals(String2, StringComparison.Ordinal)使用する場合String1 == String2は、本質的にどちらを使用するかを適切に使用String1.Equals(String2)します。デフォルトでは、大文字と小文字が区別される序数比較です。
Ghasan 2014年

3
@Ghasanそれが==「より良い」になるかどうかはわかりませんが、それはa)短く、b)正確に何をするかについて明確ではString1なく、c)比較をスローせずにnullにすることができますNullReferenceException
Eugene Beresovsky、2015

3
@Ghasanは、.NET Frameworkページ(msdn.microsoft.com/en-us/library/…)で文字を使用するための公式のMSDN ベストプラクティスでStringComparison型を明示的に指定するオーバーロードの使用を推奨しています。文字列比較の場合はを意味しString.Equalsます。
Ohad Schneider

3
@EugeneBeresovsky回避NullReferenceExceptionするには、静的メソッドを使用するだけですString.Equals(string1, string2, StringComparison.Ordinal)
Ohad Schneider

回答:


302

InvariantCulture

「標準」の文字順序セット(a、b、cなど)を使用します。これは、文字を異なる順序で並べ替える可能性がある特定のロケールとは対照的です( 'a-with-acute'は、ロケールに応じて 'a'の前または後にあります)。

序数

一方、は、文字を表す生のバイトの値のみを調べます。


さまざまなStringComparison値の結果を示す優れたサンプルがhttp://msdn.microsoft.com/en-us/library/e6883c06.aspxにあります。最後までずっと、それは示しています(抜粋):

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)がわかります。


25
序数比較では、バイトではなくコードポイントを調べます。
Joey

144
有用な情報のように感じますが、実際には質問の答えにはなりません。2つの文字列の等価性を判断するときに、序数の代わりにInvarintCultureを使用する理由はありますか?文字列の並べ替えにはInvariantCultureを使用し、同等チェックにはOrdinalを使用する必要があります(アクセント付きのaがaの前後にあることは問題ではありませんが、単純に異なります)。しかし、私自身はこの点について少し確信が持てません。
MPavlak 2012年

18
msdn.microsoft.com/en-us/library/ms230117%28v=vs.90%29.aspxを参照して、文字列の正規化と序数比較が推奨されていることを確認してください
MPavlak

23
序数の方がはるかに速い
ダレン

9
さまざまな文字列比較メソッドのそれぞれのパフォーマンスとその時間を示す、優れたパフォーマンステスト結果が公開されたC#文字列比較テストがあります。
Kumar C 14

262

それは重要です、例えば-文字拡張と呼ばれるものがあります

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

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

InvariantCultureß文字を使用すると、ssに展開されます。


1
この事はまたの間にいくつかの方法が異なりありませんOrdinalInvariantCulture?それが元の質問に関するものです。
Matthijs Wessels、

3
知らない人のために、少なくともドイツ語ではダブルsに等しいßことに注意する必要がありますß。出典:en.wikipedia.org/wiki/%C3%9F
Peter

20
@Peterは正確ではありません。ドイツ語では使用できずßss互換性もありません(私はネイティブスピーカーです)。両方が合法である場合もありますが(多くの場合、一方が古く、推奨されていません)、許可されるフォームは1つだけです。
エンツィ

5
この単純な例は、2つの比較の違いを明確に示しています。私は今これを手に入れていると思います。
BrianLegg 2017

4
試してみました:ideone.com/j8DvDoかっこいい!ドイツ語の少しのレッスン。ßとssの違いは何なのか
気に

111

.NET Frameworkで文字列を使用するためのベストプラクティスを指す

  • カルチャに依存しない文字列マッチングの安全なデフォルトとして、StringComparison.OrdinalまたはStringComparison.OrdinalIgnoreCase比較に使用します。
  • パフォーマンスを向上させるには、StringComparison.Ordinalまたはと比較してくださいStringComparison.OrdinalIgnoreCase
  • 比較が言語学的に関係がない場合(例えば、記号)に基づいて、文字列演算の代わりに非言語的StringComparison.OrdinalまたはStringComparison.OrdinalIgnoreCase値を使用しますCultureInfo.InvariantCulture

そして最後に:

  • StringComparison.InvariantCultureほとんどの場合に基づく文字列操作を使用しないでください。数少ない例外の1つは、言語的には意味があるが文化的には無関係なデータを保持している場合です。

56

もう1つの便利な違い(アクセントが一般的ではない英語の場合)は、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の比較は、最初の異なるアクセントで停止せず、アクセントと大文字小文字のほかに残りの文字列が一致する場合、同じ文字のアクセントの違いのみを考慮するように見えます。次に、アクセントの違いが前の大文字と小文字の違いの前に考慮されるため、 "Aaba" <"aába"。
Rob Parker

31

同等性についての質問ですが、簡単に視覚的に参照できるように、ここではいくつかの文化を使用して並べ替えられたいくつかの文字列の順序を示します。

Ordinal          0 9 A Ab a aB aa ab ss Ä Äb ß ä äb      
IgnoreCase       0 9 a A aa ab Ab aB ss ä Ä äb Äb ß      
--------------------------------------------------------------------
InvariantCulture 0 9 a A  ä Ä aa ab aB Ab äb Äb ss ß     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ß ss     
--------------------------------------------------------------------
da-DK            0 9 a A  ab aB Ab ss ß ä Ä äb Äb aa     
IgnoreCase       0 9 A a  Ab aB ab ß ss Ä ä Äb äb aa     
--------------------------------------------------------------------
de-DE            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
en-US            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
ja-JP            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     

観察:

  • de-DEja-JP、およびen-USソートと同じ方法
  • Invariant上記の3つの文化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));
}

1
うーん-わかりました。あなたがこの研究を行い、調査結果を投稿してくれてうれしいですが、私はあなたの要点が正確にはわかりません。とにかく、デンマーク語は「最も重要な文化」の1つではない可能性があります(ただし、500万人のデンマーク人は実際には彼らの文化が好きです)、「aa」を追加のテスト文字列として、「da-DK」を追加のテストカルチャでは、いくつかの興味深い結果が表示されます。
RenniePet 2014年

1
@RenniePetありがとうございます。デンマーク語を追加したのは、他の3つの文化が使用されているのとはかなり異なるためです。(皮肉を示す絵文字は、私が想定しているほど英語のリーディングウェブでは理解されていないようなので、私は「最も重要な文化」のコメントを削除しました。結局のところ、BCLにはCultureComparer使用できる機能が含まれていませんこの表では、Danishculture(info)が非常に重要であることが判明しました。)
Eugene Beresovsky

1
ありがとう。あなたの「最も重要な文化」のコメントは、一粒の塩で取られるように意図されていたことがわかりました-絵文字を使用するには年齢が高すぎただけです。テキストメッセージが非常に一般的になり、絵文字を使用することは、誰かが笑うかどうかに関係なく、ジョークを言った後にジョークを説明するようなものだと思います。ちなみに、他のスカンジナビアの文化(フィンランド語、ノルウェー語、スウェーデン語)は、デンマーク語と同じですが、「aa」の非常に特殊な処理を除いて、もちろんデンマーク語が優れた文化であることを証明しています。
RenniePet 2014年

1
デンマーク語では、アルファベット順でアルファベットの最後に特殊文字æ(ae)、ø(oe、ö)、およびå(aa、ä)が配置されているため、äとaaのソート方法が異なります。
Alrekr


5

以下は、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になります。


同様の例をもう1つ追加しますが、文字列リテラルを使用すると、a="\x00e9"(e急性)とb="\x0065\x0301"(eが急性アクセントと組み合わされた場合)StringComparer.Ordinal.Equals(a, b)falseをStringComparer.InvariantCulture.Equals(a, b)返し、trueを返します。
George Helyar

2

違いを示すために、凝ったユニコード文字の例を使用する必要はありません。ここで私が今日見つけた、ASCII文字のみで構成される驚くべき簡単な例を1つ示します。

ASCIIテーブルによると、通常比較すると0(0x48)は(0x95)よりも小さくなり_ます。InvariantCultureは反対のことを言います(以下のPowerShellコード):

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

-7

オーバーロードとして受け入れる文字列メソッドでは、常にInvariantCultureを使用するようにしてください。InvariantCultureを使用することで、あなたは安全な側にいます。多くの.NETプログラマはこの機能を使用しない場合がありますが、ソフトウェアが異なるカルチャで使用される場合、InvariantCultureは非常に便利な機能です。


3
ソフトウェアが異なるカルチャで使用されない場合は、Ordinalよりもはるかに遅くなります。
カイル

4
確かに無計画な反応を考えなかったので、私は反対投票を検討しました。その中には一粒の真実があります。アプリケーションが複数の文化に広がっている場合...それは、「常にInvariantCultureを使用しようとする」という最初の言葉を確かに保証するものではありませんか?反対票を受け取った後、この狂気を編集するために何年も前に戻っていないことに驚かされます。
Suamere 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.