9
11

More than 1 year has passed since last update.

.NETで全角/半角・大文字/小文字を考慮した文字列比較

Posted at

掲題の通りですが、コードの書き方はあれど結果をまとめてあるものが見当たらず毎回コードを動かして確認しているので、備忘録としてまとめます。直感と異なる挙動もあり覚えるのも容易ではありません。
環境:.NET ver 6.0.300

3行で

  • 大文字小文字を区別する/しないならStringComparisonを受け取るオーバーロードに明示的に指定
  • 全角半角の区別する/しないは癖が強く挙動に一貫性がないので注意が必要
  • .NETのバージョンによって挙動が異なりそうなので要実運用環境テスト

参考

string.Equals

等しければTrue、異なればFalse

  • StringComparison.Ordinal
"test" "TEST" "test" "TEST"
"test" True False False False
"TEST" False True False False
"test" False False True False
"TEST" False False False True
  • StringComparison.OrdinalIgnoreCase
"test" "TEST" "test" "TEST"
"test" True True False False
"TEST" True True False False
"test" False False True True
"TEST" False False True True
  • StringComparison.CurrentCulture(ja-JP)
"test" "TEST" "test" "TEST"
"test" True False True False
"TEST" False True False True
"test" True False True False
"TEST" False True False True
  • StringComparison.CurrentCultureIgnoreCase(ja-JP)
"test" "TEST" "test" "TEST"
"test" True True False False
"TEST" True True False False
"test" False False True True
"TEST" False False True True

StringComparer.Equals

string.Equalsと同様

new CultureInfo("ja-JP").CompareInfo.Compare

等しければ0、異なれば並べ替え順序によって負か正の値

  • CompareOptions.None
"test" "TEST" "test" "TEST"
"test" 0 <0 0 <0
"TEST" >0 0 >0 0
"test" 0 <0 0 <0
"TEST" >0 0 >0 0
  • CompareOptions.IgnoreCase
"test" "TEST" "test" "TEST"
"test" 0 0 <0 <0
"TEST" 0 0 <0 <0
"test" >0 >0 0 0
"TEST" >0 >0 0 0
  • CompareOptions.Ordinal
"test" "TEST" "test" "TEST"
"test" 0 >0 <0 <0
"TEST" <0 0 <0 <0
"test" >0 >0 0 >0
"TEST" >0 >0 <0 0
  • CompareOptions.OrdinalIgnoreCase
"test" "TEST" "test" "TEST"
"test" 0 0 <0 <0
"TEST" 0 0 <0 <0
"test" >0 >0 0 0
"TEST" >0 >0 0 0
  • CompareOptions.IgnoreWidth
"test" "TEST" "test" "TEST"
"test" 0 <0 0 <0
"TEST" >0 0 >0 0
"test" 0 <0 0 <0
"TEST" >0 0 >0 0
  • CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase
"test" "TEST" "test" "TEST"
"test" 0 0 0 0
"TEST" 0 0 0 0
"test" 0 0 0 0
"TEST" 0 0 0 0

考察

  • StringComparison.CurrentCultureでは全角半角を区別していないのに、StringComparison.CurrentCultureIgnoreCaseでは全角半角を区別しているあたり、直感と異なる動きとなっていて注意が必要です。StringComparison.CurrentCultureIgnoreCaseではすべてTrueになると思っていました。
  • CompareOptions.Noneでは全角半角を区別していないのに、CompareOptions.IgnoreCaseフラグを立てたとたんに全角半角を区別しているあたりもちぐはぐな動きだと思います。
  • それ以外は立てたフラグの通りの動作になっているようです。
  • 参考先では今回と異なる挙動となっていたことが読み取れます。

現在のカルチャが日本語(ja-JP)の環境で試した限りでは、どのStringComparison列挙体のメンバを使っても、全角文字と半角文字('A'と'A'、'ア'と'ア'など)を区別しないで比較することはできませんでした。

比較結果は.NETのバージョンとかによるのかもしれません。.NET での文字列の比較に関するベスト プラクティスでも

さらに、文字列比較を、異なるバージョンの .NET を使用したり、異なるオペレーティング システムまたはバージョンが異なるオペレーティング システム上の .NET で実行したりすると、異なる結果が返る可能性があります。 詳細については、「Strings and The Unicode Standard」(文字列と Unicode 標準) を参照してください。

とあります。とはいえ今回確認した挙動はUnicodeとかそういう問題じゃない気もしますが…

  • InvariantCultureは用途が限定的なので今回はスルーしています
  • CompareOptionsのフラグを見るにつけ、日本語は特別扱いされているというか、頭の痛い言語だなと思います。

まとめ

文字列比較に明示的にオプションを指定するのはプログラマの嗜みの1つですが、それもこう挙動に一貫性でないと苦労します。
仕様をしっかり把握したうえで間違いのないオプションを指定したいですね。
あとテストはちゃんとしましょう。

9
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11