web-dev-qa-db-ja.com

文字列が変更されないことが保証されている場合、文字列の比較は文化に基づいて実際に異なりますか?

暗号化された資格情報/接続文字列を構成ファイルから読み取っています。 Resharperは、この行で「String.IndexOf(string)はカルチャ固有です」と言っています。

if (line.Contains("Host=")) {
    _Host = line.Substring(line.IndexOf(
        "Host=") + "Host=".Length, line.Length - "Host=".Length);

...そしてそれを次のように変更したい:

if (line.Contains("Host=")) {
    _Host = line.Substring(line.IndexOf("Host=", System.StringComparison.Ordinal) + "Host=".Length, line.Length -   "Host=".Length);

私が読んでいる値は、アプリが展開される場所に関係なく、常に「Host =」になります。この「System.StringComparison.Ordinal」ビットを追加することは本当に賢明ですか?

さらに重要なことは、(それを使用するために)何かを傷つける可能性がありますか?

53
B. Clay Shannon

絶対に。 MSDNごと( http://msdn.Microsoft.com/en-us/library/d93tkzah.aspx )、

このメソッドは、現在のカルチャを使用して、Word(大文字と小文字を区別するおよびカルチャを区別する)検索を実行します。

(コントロールパネルの地域と言語の設定を介して)異なるカルチャの下で実行すると、異なる結果が得られる場合があります。

この特定のケースでは、おそらく問題はありませんが、検索文字列にiをスローしてトルコで実行すると、おそらくあなたの一日を台無しにします。

MSDNを参照してください: http://msdn.Microsoft.com/en-us/library/ms973919.aspx

これらの新しい推奨事項とAPIは、デフォルトの文字列APIの動作に関する誤った想定を緩和するために存在します。非言語文字列データが言語的に解釈される場合に出現するバグの標準的な例は、「トルコ語-I」問題です。

米国英語を含むほぼすべてのラテンアルファベットの場合、文字i(\ u0069)は文字I(\ u0049)の小文字バージョンです。この大文字と小文字のルールは、そのような文化でプログラミングを行う人にとってはすぐにデフォルトになります。ただし、トルコ語( "tr-TR")には、大文字の「ドット付きi」文字(\ u0130)があります。これはiの大文字バージョンです。同様に、トルコ語では、小文字の「ドットなしのi」または(\ u0131)があり、これはIを大文字にします。この動作は、アゼリ文化(「az」)でも発生します。

したがって、iを大文字にしたり、Iを小文字にしたりすることについて通常行われた仮定は、すべての文化で有効ではありません。文字列比較ルーチンのデフォルトのオーバーロードが使用される場合、それらはカルチャ間の差異の影響を受けます。次の例のように、非言語データの場合、これにより望ましくない結果が生じる可能性があります。

    Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")
Console.WriteLine("Culture = {0}",
   Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}", 
   (String.Compare("file", "FILE", true) == 0));

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
Console.WriteLine("Culture = {0}",
   Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}", 
   (String.Compare("file", "FILE", true) == 0));

Iの比較の違いにより、スレッドカルチャが変更されると、比較の結果が変わります。これは出力です:

Culture = English (United States)
(file == FILE) = True
Culture = Turkish (Turkey)
(file == FILE) = False

ケースなしの例を次に示します。

var s1 = "é"; //é as one character (ALT+0233)
var s2 = "é"; //'e', plus combining acute accent U+301 (two characters)

Console.WriteLine(s1.IndexOf(s2, StringComparison.Ordinal)); //-1
Console.WriteLine(s1.IndexOf(s2, StringComparison.InvariantCulture)); //0
Console.WriteLine(s1.IndexOf(s2, StringComparison.CurrentCulture)); //0
64
Mark Sowul

CA1309:UseOrdinalStringComparison

しません 傷つける 使用しないが、「パラメーターをStringComparison.OrdinalまたはStringComparison.OrdinalIgnoreCaseに明示的に設定することにより、コードの速度が向上し、正確性が向上し、信頼性が向上します。「。


Ordinalとは正確に何であり、なぜあなたのケースにとって重要なのですか?

順序ソート規則を使用する操作は、文字列内の各Charの数値(Unicodeコードポイント)に基づいて比較を実行します。序数の比較は高速ですが、文化に依存しません。序数の並べ替え規則を使用してUnicode文字(U +)で始まる文字列を並べ替えると、xxxxの値が数値的にyyyyより小さい場合、文字列U + xxxxが文字列U + yyyyの前に来ます。

そして、あなたが述べたように...あなたが読んでいる文字列値は文化に敏感ではないので、Word比較ではなく序数比較を使用するのが理にかなっています。ただ覚えておいてください、序数は「これは文化に敏感ではない」という意味です。

27
m-y

特定の質問に答えるには:いいえ。ただし、静的分析ツールは、入力値にロケール固有の情報が含まれないことを認識できません。