C#の文字列比較メソッドの違い


261

C#での文字列の比較は非常に簡単です。実際には、いくつかの方法があります。以下のブロックにいくつかリストしました。私が気になるのは、それらの間の違いと、1つを他のどれよりもいつ使用すべきかです。絶対に避けるべきですか?リストにないものはありますか?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(注:この例では、同等または同等以上の値を求めていますが、それ以上でも以下でも構いません)


4
一つのトラップはあなたがnullのメソッドを呼び出すことができると仮定しているようなあなたがstringValue.Equals(null)を行うことができないです
JOHNC


@RobertHarvey私がstackoverflowに来た理由は、答えを得るために複数のページを読む必要がないようにするためです。
Syaiful Nizam Yahya

@Syaiful:私がStack Overflowに来る理由は、ドキュメントにない回答を見つけるためです。
Robert Harvey

回答:


231

これらの機能の動作規則は次のとおりです。

stringValue.CompareTo(otherStringValue)

  1. null 文字列の前に来る
  2. を使用しますCultureInfo.CurrentCulture.CompareInfo.Compare。つまり、カルチャに依存した比較を使用します。これは、ドイツまたはß同等のものと比較することを意味するかもしれませんSS

stringValue.Equals(otherStringValue)

  1. null 何にも等しいとは見なされません
  2. StringComparisonオプションを指定しない限り、言語や文化に関係ßなく、直接の序数等価チェックのように見えます。つまり、とは異なりSSます。

stringValue == otherStringValue

  1. と同じではありませんstringValue.Equals()
  2. ==オペレータは、静的呼び出し、Equals(string a, string b)今度は内部に行く方法(EqualsHelper比較を行うことを。
  3. 呼び出し.Equals()null文字列と、取得するnullには、一方で、参照例外は==ありません。

Object.ReferenceEquals(stringValue, otherStringValue)

参照が同じであることを確認するだけです。つまり、同じ内容の2つの文字列だけではなく、文字列オブジェクトをそれ自体と比較します。


メソッド呼び出しを使用する上記のオプションを使用すると、比較方法を指定するための追加オプションを持つオーバーロードがあることに注意してください。

等しいかどうかを確認するだけの場合のアドバイスは、カルチャに依存する比較を使用するかどうかを決定し、選択に応じて.CompareToor を使用.Equalsすることです。


5
「stringValue.Equals(otherStringValue):nullはnullと等しくない」笑、そうではないと思います。nullはObjectReferenceNotSet例外と同じです。
ケビン・

29
==は.Equals()と同じではありません... ==演算子は静的Equals(string a、string b)メソッドを呼び出します(次に、内部のEqualsHelperに移動して比較を行います。nullで.Equalsを呼び出します文字列はnull参照exc。を取得しますが、==は取得しません
Dan C.

2
一方、.Equalsは少し高速ですが(内部ではメソッド呼び出しが1つ少なくなります)、可読性は低くなります-もちろん、もちろん:)。
ダンC.

「==」は参照比較を行い、object.equalsは値の比較を行うと考えていましたが、「==」とstring.equalsは同じように機能しますか?
amesh 2012

@ LasseV.Karlsenについてどう思いますString.Compareか?
JDandChips

72

MSDNから:

「CompareToメソッドは、主にソートまたはアルファベット順の操作で使用するために設計されました。2つの文字列が等しいかどうかを判断することがメソッド呼び出しの主な目的である場合は使用しないでください。2つの文字列が等しいかどうかを判断するには、Equalsメソッドを呼び出します。 」

彼らは、平等のみを求める場合の.Equals代わりに使用することを提案し.CompareToています。間に差がある場合、私はわからない.Equals==のためのstringクラスが。後で誰かが来て、そのクラスの演算子を再定義する場合に備えて、自分のクラスの代わりに、.EqualsまたはObject.ReferenceEquals代わりに使用します。====


18
それはあなたに起こったことがありますか?(再定義==)...私はそれがwaaaayの防御的プログラミングと見なします=)
juan

はい、それがオブジェクトの等価性を探しているときにObject.ReferenceEqualsを使用する理由です:)。それは少し過剰な防御になるかもしれませんが、私はそれについて熱狂的ではなく、本当にこの状況はあまり頻繁に現れません。
Ed S.

この「防御的コーディング」が役立つとは思えません。クラスの所有者が==演算子をオーバーライドする必要がある場合、誰もそれを使用していないことがわかりますか?
Dave Van den Eynde、2012

1
@DaveVandenEynde:ええ...私はしばらく前にこれを書いた。私はこれを定期的に行うのではなく、適切な場合にのみ.Equalsをオーバーライドします。
Ed S.

1
JJS

50

BCLメソッドの違いに興味があるなら、Reflectorがお勧めです:-)

私はこれらのガイドラインに従います:

完全一致: 編集:以前は常に==演算子を使用していましたが、Equals(string、string)の内部ではオブジェクト==演算子を使用してオブジェクト参照を比較していますが、strA.Equals(strB)は依然として1-11%のようですstring.Equals(strA、strB)、strA == strB、およびstring.CompareOrdinal(strA、strB)よりも全体的に高速です。インターンされた/インターンされていない両方の文字列値、同じ/異なる文字列長、およびさまざまなサイズ(1B〜5MB)のストップウォッチでループテストを行いました。

strA.Equals(strB)

人間が読み取れる一致(西洋文化、大文字と小文字を区別しない):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

人間が読み取れる一致(他のすべてのカルチャ、CultureInfoで定義された大文字と小文字の区別、アクセント/カナなど):

string.Compare(strA, strB, myCultureInfo) == 0

カスタムルールによる人間が読める形式の一致(他のすべての文化):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0

18

エドは言った、のCompareToは、ソートに使用されます。

ただし、.Equalsと==の間には違いがあります。

== 本質的に次のコードに解決されます:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

単純な理由は、以下が例外をスローすることです。

string a = null;
string b = "foo";

bool equal = a.Equals(b);

そして、以下はしません:

string a = null;
string b = "foo";

bool equal = a == b;

15

文字列比較の問題に関する適切な説明と実践は、Microsoft .NET 2.0で文字列を使用するための新しい推奨事項、および.NET Frameworkで文字列を使用するためのベストプラクティスにも記載されています


上記の各方法(およびその他)には特定の目的があります。それらの主な違いは、デフォルトで使用するStringComparison Enumerationの種類です。いくつかのオプションがあります:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • 序数
  • OrdinalIgnoreCase

上記の比較タイプはそれぞれ、異なるユースケースを対象としています。

  • 序数
    • 大文字と小文字を区別する内部識別子
    • XMLやHTTPなどの標準の大文字と小文字を区別する識別子
    • 大文字と小文字を区別するセキュリティ関連の設定
  • OrdinalIgnoreCase
    • 大文字と小文字を区別しない内部識別子
    • XMLやHTTPなどの標準の大文字と小文字を区別しない識別子
    • ファイルパス(Microsoft Windows)
    • レジストリキー/値
    • 環境変数
    • リソース識別子(ハンドル名など)
    • 大文字と小文字を区別しないセキュリティ関連の設定
  • InvariantCultureまたはInvariantCultureIgnoreCase
    • 一部の永続的な言語的に関連するデータ
    • 固定されたソート順を必要とする言語データの表示
  • CurrentCultureまたはCurrentCultureIgnoreCase
    • ユーザーに表示されるデータ
    • ほとんどのユーザー入力

.NET 2.0以降、StringComparison列挙型と文字列比較メソッドのオーバーロードが存在することに注意してください。


String.CompareToメソッド(文字列)

IComparable.CompareToメソッドの実際のタイプセーフな実装です。デフォルトの解釈:CurrentCulture。

使用法:

CompareToメソッドは、主にソートまたはアルファベット順の操作で使用するために設計されました

したがって

IComparableインターフェイスを実装すると、必ずこのメソッドが使用されます

String.Compareメソッド

多くのオーバーロードを持つStringクラスの静的メンバー。デフォルトの解釈:CurrentCulture。

可能な限り、StringComparisonパラメーターを含むCompareメソッドのオーバーロードを呼び出す必要があります。

String.Equalsメソッド

Objectクラスからオーバーライドされ、型安全のためにオーバーロードされます。デフォルトの解釈:序数。次のことに注意してください。

Stringクラスの等価メソッドには、静的Equals静的演算子==、およびインスタンスメソッドEqualsが含まれます。


StringComparerクラス

特にソートを目的とした文字列比較を処理する別の方法もあります。

StringComparerクラスを使用して、型固有の比較を作成し、ジェネリックコレクションの要素を並べ替えることができます。Hashtable、Dictionary、SortedList、SortedListなどのクラスは、ソートの目的でStringComparerクラスを使用します。


2
SOに関する他の投稿によると、序数以外のすべてのメソッドにはCompare(a、b)とCompare(b、a)の両方が1を返す場合があり、バグは「修正されない」と分類されています」そのため、そのような比較にユースケースがあるどうかはわかりません。
スーパーキャット2014

@supercatにリンクできますか、それとも例を挙げられますか?
Noctis 2014年

1
この問題については、stackoverflow.com / questions / 17599084 /…をご覧ください。
スーパーキャット2014年

7

通常、これを実行する必要がある時間の99%ではパフォーマンスは重要ではありませんが、これをループで数百万回実行する必要がある場合は、.Equalsまたは==を使用することを強くお勧めします。それが一致しないと、すべてがfalseとしてスローされますが、CompareToを使用する場合は、どの文字が他の文字よりも小さいかを判別する必要があるため、パフォーマンス時間がわずかに低下します。

アプリをさまざまな国で実行する場合は、CultureInfoの影響を確認し、.Equalsを使用することをお勧めします。私は本当に米国向けのアプリを作成しているだけなので(誰かが正しく機能しなくてもかまいません)、常に==を使用します。


5

ここにリストしたフォームでは、2つの間に大きな違いはありません。 現在のカルチャを使用して比較をCompareTo行うCompareInfoメソッドを呼び出すことになります。オペレーターEqualsによって呼び出され==ます。

オーバーロードを検討すると、状況が異なります。 Compareまた==、現在のカルチャを使用して文字列を比較することしかできません。 EqualsそしてString.CompareStringComparisonカルチャを区別しないか大文字と小文字を区別しない比較を指定できる列挙引数を取ることができます。のみString.Compare、指定することを可能にするCultureInfoと、デフォルトの文化以外の文化を使用して比較を行います。

汎用性があるため、String.Compare他のどの比較方法よりも多く使用しています。自分が欲しいものを正確に指定できます。


2

注意すべき1つの大きな違いは、最初の文字列がnullの場合、.Equals()は例外をスローしますが、==はそうではありません。

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");

0
  • s1.CompareTo(s2): 主な目的が2つの文字列が等しいかどうかを判断することである場合は使用しないでください
  • s1 == s2: 大文字小文字を区別できません
  • s1.Equals(s2、StringComparison): s1がnullの場合、NullReferenceExceptionをます
  • String.Equals(s2、StringComparison): 除去のプロセスにより、この静的メソッドはWINNERです(2つの文字列が等しいかどうかを判断する一般的な使用例を想定しています)。


-9

.Equalsを使用すると、StringComparisonオプションも取得できます。大文字と小文字などを無視するのに非常に便利です。

ところで、これはfalseと評価されます

string a = "myString";
string b = "myString";

return a==b

==はaとb(ポインタ)の値を比較するため、ポインタがメモリ内の同じオブジェクトを指している場合にのみ、trueと評価されます。.Equalsはポインターを逆参照し、ポインターに格納されている値を比較します。ここではa.Equals(b)が真になります。

bを次のように変更した場合:

b = "MYSTRING";

次に、a.Equals(b)はfalseですが、

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

本当だろう

a.CompareTo(b)は、ポインターの値を比較する文字列のCompareTo関数を呼び出し、aに格納された値がbに格納された値より小さい場合は<0を返し、a.Equals(b)がtrueの場合は0を返します。それ以外の場合は> 0。ただし、これは大文字と小文字が区別されるため、CompareToで大文字と小文字を区別するためのオプションなどがあると思いますが、今見る時間はありません。他の人がすでに述べたように、これはソートのために行われます。この方法で等価性を比較すると、不必要なオーバーヘッドが発生します。

きっと何かを除外することになると思いますが、詳細が必要な場合は、これで実験を始めるのに十分な情報になると思います。


9
a == bの部分は正しくありません。==演算子は、Stringクラスに対して効果的にオーバーロードされ、実際の参照に関係なく値を比較します。
Goyuix 2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.