こんにちは、働くC#プログラマーのさんさめです。
C#で文字列比較をするのは、
特に難しいことはありません。
普通に比較演算子「==」で比較すれば
一致かどうか確認できます。
var str = "Hoge";
if (str == "Hoge")
{
// True! ここには入ってくる
}
ところが、
「==」で結ぶやり方では、
「Hoge」と「hoge」のように、
大文字小文字が異なるだけの文字列は
不一致とみなされます。
var str = "Hoge";
if (str == "hoge")
{
// False…ここには入ってこない
}
大文字小文字を区別せずに文字列を比較したい場合は、
Equalsメソッドと、その引数である
StringComparison.OrdinalIgnoreCaseを使えばOKです。
string.Equals("Hoge", "hoge", StringComparison.OrdinalIgnoreCase);
え?両方ToUpper
して比較すれば良いんじゃ…
もちろんそれでも良いです。
ただ、今回紹介する方法を使った方が、
ToUpperやToLowerを使うよりもシンプルに記述できます。
詳しく解説していきます。
string.EqualsにOrdinalIgnoreCaseを指定して比較する
string.Equalsには、
文字列の比較規則を指定できるオーバーロードがあります。
- インスタンスメソッドの
Equals(string value, StringComparison comparisonType) - 静的メソッドの
Equals(string a, string b, StringCompaison comparisonType)
の2つです。
この第2引数(静的メソッドの場合は第3引数)に、
OrdinalIgnoreCaseを指定することで、
大文字小文字を区別せずに比較を行うことができます。
具体的なサンプルコードです。
var a = "Hoge";
// ↓はfalse。「==」では大文字小文字を区別する
Console.WriteLine(a == "hoge");
// ↓はtrue。OrdinalIgnoreCaseを指定すると
// 大文字小文字を区別しない
Console.WriteLine(a.Equals("hoge", StringComparison.OrdinalIgnoreCase));
// ↓もtrue。静的メソッドを使う場合の書き方
Console.WriteLine(string.Equals(a, "hoge", StringComparison.OrdinalIgnoreCase));
多少記述量は増えますが、
大文字小文字を区別しないで比較したい時は、
これだけで大丈夫です。
わざわざ関数を自作しなくて良いということですね。
ちなみに、OrdinalIgnoreCase以外にも、
「なんたらIgnoreCase」が2つほどありますが、
どちらも日本では使いません。
しかも、他2つは無駄に処理も重くなってしまいます。
- 大文字小文字を区別したいならOrdinalIgnoreCase
- そうでないなら普通に「==」で比較
と覚えておけば充分です。
静的メソッドなら絶対にnull参照例外にならないのでオススメ
さて、先ほど述べたようにstring.Equalsには
インスタンスメソッドと、
静的メソッドがあります。
結果が同じなんだから、
どっちを使っても良いよね?
いいえ、そんなことはありません。
絶対に静的メソッドの方を使った方が良いです。
なぜなら、インスタンスメソッドの方は、
null参照例外になる可能性があるからです。
先ほどのコードを少し変えて、
変数aにnullを入れてみましょう。
string a = null;
// ↓はfalse。大文字小文字は区別できないが安全
Console.WriteLine(a == "hoge");
// ↓は例外。aがnullなのでNullReferenceExceptionになる
Console.WriteLine(a.Equals("hoge", StringComparison.OrdinalIgnoreCase));
// ↓はfalse。大文字小文字を区別しつつ安全
そして実行すると…
この通り、例外になってしまいました。
このように、インスタンスメソッドを使った場合は、
そのインスタンスがnullの時に例外になってしまいます。
どんな値が来るか分からない場合、
安全のために静的メソッドの方を使いましょう。
OrdinalIgnoreCaseが使える他の関数
OrdinalIgnoreCaseの指定は、
Equalsメソッド以外にも
以下の関数で使えます。
- StartsWith
- EndsWith
- IndexOf
- LastIndexOf
- Contains
- Compare(静的メソッド)
文字列比較ができるメソッドは、
ほとんど対応していることになりますね。
逆に、以下のメソッドでは指定ができません。
- Split
- CompareTo
- ただし、静的メソッドのCompareを使えばよい
Splitの分割に使う文字列の指定で、
大文字小文字を区別しないようにするときは、
「a」と「A」両方を指定する必要があるということですね。
とはいえ、Splitの分割に使う文字には、
多くの場合「 (半角スペース)」や「,」など、
アルファベット以外を指定することがほとんどなので、
日常で困ることはほぼないでしょう。
Dictionaryのキーに使う場合はToUpperなどを使うしかない
単純な文字列の比較であれば、
大文字小文字を区別しないためには、
StringComparison.OrdinalIgnoreCaseを
使えばよいことを説明しました。
ところが、Dictionaryのキーとして文字列を使い、
なおかつ大文字小文字を区別したくない場合は、
この指定を使うことはできません。
そのため、そのような使い方をしたい場合には、
あらかじめToUpper(Invariant)を呼んで
正規化しておく必要があります。
サンプルコードです。
var dic = new Dictionary<string, string>();
dic.Add("hoge", "Foo");
// ↓はfalse。
Console.WriteLine(dic.ContainsKey("Hoge"));
// 辞書のキーで大文字小文字を区別したくない場合は、
// あらかじめToUpperなどで揃えておく必要がある
dic.Add("fuga".ToUpperInvariant(), "Bar");
// ↓はtrue
Console.WriteLine(dic.ContainsKey("Fuga".ToUpperInvariant()));
ToUpperInvariantは
.NET の文字列を使用するためのベスト プラクティス
に書かれているように、
OrdinalIgnoreCaseを指定したときに
内部処理で使われているメソッドです。
ただ、ここ日本では、
別にToUpperを使っても問題ありません。
記述量も増えるので、
私はこのようなケースでも
ToUpperしか使っておりません。
まとめ
まとめです。
- 文字列の大文字小文字を区別しないで比較するには、
string.Equalsと、
StringComparison.OrdinalIgnoreCaseを使う - ContainsやEndsWithなど
文字列比較が絡むメソッドでは大体使える - 辞書のキーで大文字小文字を区別したくない場合は、
あらかじめToUpperなどで揃えておく必要がある
最後までお読みいただき、ありがとうございました。
関連記事
関連記事です。
大文字小文字を区別したくない
…の最たるものがファイルパスでしょう。
ただし、ユーザーに情報を見せる必要があるときは、
大文字小文字が正確な方が良いですね。
大文字小文字を区別してファイルパスを取得する
で紹介している方法を使えば、それが実現できます。
コメント