.NET の文字列を使用するためのベスト プラクティスBest Practices for Using Strings in .NET

.NET には、ローカライズされたアプリケーションやグローバル化されたアプリケーションを開発するための広範なサポートが用意されており、文字列の並べ替えや表示などの一般的な操作を実行するときに、現在のカルチャの規則や特定のカルチャの規則を簡単に適用できるようになっています。.NET provides extensive support for developing localized and globalized applications, and makes it easy to apply the conventions of either the current culture or a specific culture when performing common operations such as sorting and displaying strings. しかし、文字列の並べ替えや比較の操作は、必ずしもカルチャに依存するとは限りません。But sorting or comparing strings is not always a culture-sensitive operation. たとえば、アプリケーションが内部で使用する文字列は、通常、すべてのカルチャで同じように処理される必要があります。For example, strings that are used internally by an application typically should be handled identically across all cultures. XML タグ、HTML タグ、ユーザー名、ファイル パス、システム オブジェクトの名前などのカルチャに依存しない文字列データがカルチャに依存するかのように解釈されると、アプリケーション コードで軽度のバグが発生したり、パフォーマンスが低下したり、場合によってはセキュリティの問題を引き起こしたりする可能性があります。When culturally independent string data, such as XML tags, HTML tags, user names, file paths, and the names of system objects, are interpreted as if they were culture-sensitive, application code can be subject to subtle bugs, poor performance, and, in some cases, security issues.

このトピックでは、.NET の文字列の並べ替え、比較、および大文字と小文字の区別のメソッドについて検討し、適切な文字列処理メソッドを選択するための推奨事項と、文字列処理メソッドに関する追加情報を紹介します。This topic examines the string sorting, comparison, and casing methods in .NET, presents recommendations for selecting an appropriate string-handling method, and provides additional information about string-handling methods. また、数値データ、日時データなど、書式付きデータを表示および格納のために処理する方法についても説明します。It also examines how formatted data, such as numeric data and date and time data, is handled for display and for storage.

このトピックは、次のセクションで構成されています。This topic contains the following sections:

文字列の使用に関する推奨事項Recommendations for String Usage

.NET による開発で文字列を使用するときには以下の簡単な推奨事項に従ってください。When you develop with .NET, follow these simple recommendations when you use strings:

文字列を使用する際に避ける必要があることを次に示します。Avoid the following practices when you use strings:

  • 文字列操作に対して文字列比較の規則を明示的または暗黙的に指定しないオーバーロードは使用しないでください。Do not use overloads that do not explicitly or implicitly specify the string comparison rules for string operations.

  • ほとんどの場合、StringComparison.InvariantCulture に基づく文字列操作は使用しないでください。Do not use string operations based on StringComparison.InvariantCulture in most cases. 数少ない例外の 1 つは、言語的な意味を持つがカルチャには依存しないデータを永続化する場合です。One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.

  • 2 つの文字列が等価かどうかを確認する場合に、String.Compare メソッドまたは CompareTo メソッドのオーバーロードで戻り値が 0 かどうかをテストする方法は使用しないでください。Do not use an overload of the String.Compare or CompareTo method and test for a return value of zero to determine whether two strings are equal.

  • 数値データや日時データを文字列形式で保持する場合は、カルチャに依存する書式設定を使用しないでください。Do not use culture-sensitive formatting to persist numeric data or date and time data in string form.

ページのトップへBack to top

文字列比較の明示的な指定Specifying String Comparisons Explicitly

.NET の文字列操作メソッドは、ほとんどがオーバーロードされています。Most of the string manipulation methods in .NET are overloaded. 通常は、既定の設定をそのまま使用する 1 つまたは複数のオーバーロードと、既定の設定を使用せずに文字列の比較または操作の正確な方法を定義するその他のオーバーロードがあります。Typically, one or more overloads accept default settings, whereas others accept no defaults and instead define the precise way in which strings are to be compared or manipulated. 既定の設定に依存しないメソッドには、ほとんどの場合、 StringComparison型のパラメーターが含まれています。これは、カルチャおよび大文字と小文字の区別によって文字列比較の規則を明示的に指定する列挙型です。Most of the methods that do not rely on defaults include a parameter of type StringComparison, which is an enumeration that explicitly specifies rules for string comparison by culture and case. StringComparison 列挙型のメンバーを次の表に示します。The following table describes the StringComparison enumeration members.

StringComparison のメンバーStringComparison member 説明Description
CurrentCulture 現在のカルチャを使用して、大文字と小文字を区別する比較を実行します。Performs a case-sensitive comparison using the current culture.
CurrentCultureIgnoreCase 現在のカルチャを使用して、大文字と小文字を区別しない比較を実行します。Performs a case-insensitive comparison using the current culture.
InvariantCulture インバリアント カルチャを使用して、大文字と小文字を区別する比較を実行します。Performs a case-sensitive comparison using the invariant culture.
InvariantCultureIgnoreCase インバリアント カルチャを使用して、大文字と小文字を区別しない比較を実行します。Performs a case-insensitive comparison using the invariant culture.
Ordinal 序数に基づく比較を実行します。Performs an ordinal comparison.
OrdinalIgnoreCase 大文字と小文字を区別しない、序数に基づく比較を実行します。Performs a case-insensitive ordinal comparison.

たとえば、文字または文字列に一致する String オブジェクト内の部分文字列のインデックスを返す IndexOf メソッドには、次の 9 つのオーバーロードがあります。For example, the IndexOf method, which returns the index of a substring in a String object that matches either a character or a string, has nine overloads:

次のような理由から、既定値を使用しないオーバーロードを選択することをお勧めします。We recommend that you select an overload that does not use default values, for the following reasons:

  • 既定のパラメーターを持つオーバーロードには、序数に基づく比較を実行するもの (文字列インスタンスで Char を検索するもの) と、カルチャに依存するもの (文字列インスタンスで文字列を検索するもの) があります。Some overloads with default parameters (those that search for a Char in the string instance) perform an ordinal comparison, whereas others (those that search for a string in the string instance) are culture-sensitive. どのメソッドがどの既定値を使用するのかを覚えておくのは容易ではなく、使用するオーバーロードを間違えやすくなります。It is difficult to remember which method uses which default value, and easy to confuse the overloads.

  • メソッド呼び出しで既定値に依存するコードは、意図が不明確になります。The intent of the code that relies on default values for method calls is not clear. 既定値に依存する次の例では、2 つの文字列の序数に基づく比較と言語に基づく比較のどちらを開発者が意図しているのかや、protocol と "http" の大文字と小文字が違っていた場合に等価性テストで false を返すかどうかがわかりにくくなっています。In the following example, which relies on defaults, it is difficult to know whether the developer actually intended an ordinal or a linguistic comparison of two strings, or whether a case difference between protocol and "http" might cause the test for equality to return false.

    string protocol = GetProtocol(url);       
    if (String.Equals(protocol, "http")) {
       // ...Code to handle HTTP protocol.
    }
    else {
       throw new InvalidOperationException();
    }
    
    Dim protocol As String = GetProtocol(url)       
    If String.Equals(protocol, "http") Then
       ' ...Code to handle HTTP protocol.
    Else
       Throw New InvalidOperationException()
    End If   
    

一般的には、既定値に依存しないメソッドを呼び出すことをお勧めします。そうすると、コードの意図が明確になります。In general, we recommend that you call a method that does not rely on defaults, because it makes the intent of the code unambiguous. その結果、コードが読みやすくなるため、デバッグや保守も容易になります。This, in turn, makes the code more readable and easier to debug and maintain. 次の例では、前の例で発生した問題に対応します。The following example addresses the questions raised about the previous example. 序数比較を使用することと、大文字と小文字の違いを無視することを指定します。It makes it clear that ordinal comparison is used and that differences in case are ignored.

string protocol = GetProtocol(url);       
if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}
Dim protocol As String = GetProtocol(url)       
If String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase) Then
   ' ...Code to handle HTTP protocol.
Else
   Throw New InvalidOperationException()
End If   

ページのトップへBack to top

文字列比較の詳細The Details of String Comparison

文字列比較は、多くの文字列関連操作 (特に並べ替えおよび等価性テスト) の中核です。String comparison is the heart of many string-related operations, particularly sorting and testing for equality. 文字列は、決まった順序で並べられています。たとえば、文字列の並べ替え済みリストで "my" が "string" の前にある場合は、比較で "my" が "string" 以下になる必要があります。Strings sort in a determined order: If "my" appears before "string" in a sorted list of strings, "my" must compare less than or equal to "string". また、比較は等価性を暗黙的に定義します。Additionally, comparison implicitly defines equality. 比較演算では、等価と見なされた文字列に対して 0 が返されます。The comparison operation returns zero for strings it deems equal. これは、どちらの文字列ももう一方の文字列より小さくないという意味に解釈するとわかりやすくなります。A good interpretation is that neither string is less than the other. 文字列に関係する、意味のある操作のほとんどには、他の文字列との比較か、正しく定義された並べ替え操作の実行のいずれかまたは両方の処理が含まれています。Most meaningful operations involving strings include one or both of these procedures: comparing with another string, and executing a well-defined sort operation.

注意

Windows オペレーティング システムの並べ替え操作と比較操作で使用される文字の重みに関する情報を含む一連のテキスト ファイルである並べ替え重みテーブル と、Linux と macOS 用の並べ替え重みテーブルの最新バージョンである デフォルト Unicode 照合基本テーブルをダウンロードできます。You can download the Sorting Weight Tables, a set of text files that contain information on the character weights used in sorting and comparison operations for Windows operating systems, and the Default Unicode Collation Element Table, the latest version of the sort weight table for Linux and macOS. Linux と macOS での並べ替え重みのテーブルの特定のバージョンは、システムにインストールされている International Components for Unicode ライブラリのバージョンによって異なります。The specific version of the sort weight table on Linux and macOS depends on the version of the International Components for Unicode libraries installed on the system. 実装される ICU のバージョンと Unicode のバージョンに関する情報は、ICU のダウンロードに関する記事を参照してください。For information on ICU versions and the Unicode versions that they implement, see Downloading ICU.

しかし、2 つの文字列の等価性や並べ替え順序を評価する場合、正しい結果は 1 つではありません。結果は、文字列の比較に使用される基準に依存するためです。However, evaluating two strings for equality or sort order does not yield a single, correct result; the outcome depends on the criteria used to compare the strings. 特に、序数に基づく文字列比較や、現在のカルチャまたはインバリアント カルチャ (英語をベースとする、ロケールに依存しないカルチャ) の大文字と小文字の規則や並べ替えの規則に基づく文字列比較では、さまざまな結果が返される可能性があります。In particular, string comparisons that are ordinal or that are based on the casing and sorting conventions of the current culture or the invariant culture (a locale-agnostic culture based on the English language) may produce different results.

さらに、文字列比較を、異なるバージョンの .NET を使用したり、異なるオペレーティング システムまたはバージョンが異なるオペレーティング システム上の .NET で実行したりすると、異なる結果が返る可能性があります。In addition, string comparisons using different versions of .NET or using .NET on different operating systems or operating system versions may return different results. 詳細については、「Strings and The Unicode Standard」(文字列と Unicode 標準) を参照してください。For more information, see Strings and the Unicode Standard.

現在のカルチャを使用する文字列比較String Comparisons that Use the Current Culture

文字列を比較するときの基準として現在のカルチャの規則が使用される場合があります。One criterion involves using the conventions of the current culture when comparing strings. 現在のカルチャに基づく比較では、スレッドの現在のカルチャ (ロケール) が使用されます。Comparisons that are based on the current culture use the thread's current culture or locale. ユーザーがカルチャを設定していない場合は、コントロール パネルの [地域のオプション] ウィンドウの設定が既定で使用されます。If the culture is not set by the user, it defaults to the setting in the Regional Options window in Control Panel. 言語的な意味を持つデータや、カルチャに依存したユーザー操作を反映するデータに対しては、常に現在のカルチャに基づく比較を使用する必要があります。You should always use comparisons that are based on the current culture when data is linguistically relevant, and when it reflects culture-sensitive user interaction.

しかし、.NET の比較や大文字と小文字の区別の動作は、カルチャによって変わります。However, comparison and casing behavior in .NET changes when the culture changes. たとえば、開発されたコンピューターとは異なるカルチャのコンピューターでアプリケーションが実行された場合や、実行中のスレッドのカルチャが変更された場合などに、この変化が生じます。This happens when an application executes on a computer that has a different culture than the computer on which the application was developed, or when the executing thread changes its culture. これは意図的な動作ですが、多くの開発者にはまだあまり知られていません。This behavior is intentional, but it remains non-obvious to many developers. 次の例は、英語 (米国) ("en-US") とスウェーデン語 ("sv-SE") のカルチャの並べ替え順序の違いを示しています。The following example illustrates differences in sort order between the U.S. English ("en-US") and Swedish ("sv-SE") cultures. 並べ替えられた文字列配列で、"ångström"、"Windows"、および "Visual Studio" の位置が違っていることに注目してください。Note that the words "ångström", "Windows", and "Visual Studio" appear in different positions in the sorted string arrays.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string[] values= { "able", "ångström", "apple", "Æble", 
                         "Windows", "Visual Studio" };
      Array.Sort(values);
      DisplayArray(values);

      // Change culture to Swedish (Sweden).
      string originalCulture = CultureInfo.CurrentCulture.Name;
      Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
      Array.Sort(values);
      DisplayArray(values);

      // Restore the original culture.
      Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
    }
    
    private static void DisplayArray(string[] values)
    {
      Console.WriteLine("Sorting using the {0} culture:",  
                        CultureInfo.CurrentCulture.Name);
      foreach (string value in values)
         Console.WriteLine("   {0}", value);

      Console.WriteLine();
    }
}
// The example displays the following output:
//       Sorting using the en-US culture:
//          able
//          Æble
//          ångström
//          apple
//          Visual Studio
//          Windows
//       
//       Sorting using the sv-SE culture:
//          able
//          Æble
//          apple
//          Windows
//          Visual Studio
//          ångström
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim values() As String = { "able", "ångström", "apple", _
                                 "Æble", "Windows", "Visual Studio" }
      Array.Sort(values)
      DisplayArray(values)

      ' Change culture to Swedish (Sweden).
      Dim originalCulture As String = CultureInfo.CurrentCulture.Name
      Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
      Array.Sort(values)
      DisplayArray(values)

      ' Restore the original culture.
      Thread.CurrentThread.CurrentCulture = New CultureInfo(originalCulture)
    End Sub
    
    Private Sub DisplayArray(values() As String)
      Console.WRiteLine("Sorting using the {0} culture:", _ 
                        CultureInfo.CurrentCulture.Name)
      For Each value As String In values
         Console.WriteLine("   {0}", value)
      Next
      Console.WriteLine()   
    End Sub
End Module
' The example displays the following output:
'       Sorting using the en-US culture:
'          able
'          Æble
'          ångström
'          apple
'          Visual Studio
'          Windows
'       
'       Sorting using the sv-SE culture:
'          able
'          Æble
'          apple
'          Windows
'          Visual Studio
'          ångström

現在のカルチャを使用する、大文字と小文字を区別しない比較は、スレッドの現在のカルチャの大文字と小文字の区別の規則が無視される以外は、カルチャに依存した比較と同じです。Case-insensitive comparisons that use the current culture are the same as culture-sensitive comparisons, except that they ignore case as dictated by the thread's current culture. この動作も、並べ替え順序に影響する場合があります。This behavior may manifest itself in sort orders as well.

現在のカルチャのセマンティクスを使用する比較は、次のメソッドで既定で使用されます。Comparisons that use current culture semantics are the default for the following methods:

どのような場合でも、 StringComparison パラメーターを持つオーバーロードを呼び出して、メソッド呼び出しの意図を明確にすることをお勧めします。In any case, we recommend that you call an overload that has a StringComparison parameter to make the intent of the method call clear.

非言語的な文字列データが言語的に解釈されたり、特定のカルチャの文字列データが別のカルチャの規則で解釈されたりすると、軽度のバグやあまり軽度でないバグが発生する可能性があります。Subtle and not so subtle bugs can emerge when non-linguistic string data is interpreted linguistically, or when string data from a particular culture is interpreted using the conventions of another culture. その典型的な例が、トルコ語の I の問題です。The canonical example is the Turkish-I problem.

英語 (米国) を含むほぼすべてのラテン アルファベットでは、文字 "i" (\u0069) は "I" (\u0049) の小文字版です。For nearly all Latin alphabets, including U.S. English, the character "i" (\u0069) is the lowercase version of the character "I" (\u0049). この大文字と小文字の規則は、このようなカルチャでプログラミングを行う人にとってはすぐに当たり前のことになります。This casing rule quickly becomes the default for someone programming in such a culture. しかし、トルコ語 ("tr-TR") のアルファベットには、"i" の大文字版である "ドット付きの I" ("İ" (\u0130)) があります。However, the Turkish ("tr-TR") alphabet includes an "I with a dot" character "İ" (\u0130), which is the capital version of "i". 大文字にすると "I" になる小文字の "ドットなしの i" ("ı" (\u0131)) もあります。Turkish also includes a lowercase "i without a dot" character, "ı" (\u0131), which capitalizes to "I". この動作は、アゼルバイジャン語 ("az") のカルチャでも発生します。This behavior occurs in the Azerbaijani ("az") culture as well.

したがって、"i" を大文字にしたり "I" を小文字にしたりする動作に関する前提は、すべてのカルチャで有効なわけではありません。Therefore, assumptions made about capitalizing "i" or lowercasing "I" are not valid among all cultures. 文字列比較ルーチンの既定のオーバーロードを使用すると、カルチャ間の差異の影響を受けることになります。If you use the default overloads for string comparison routines, they will be subject to variance between cultures. また、非言語的なデータを比較する場合も、既定のオーバーロードを使用すると望ましくない結果が返される可能性があります。たとえば次の例では、文字列 "file" と "FILE" の大文字と小文字を区別しない比較を実行しようとしています。If the data to be compared is non-linguistic, using the default overloads can produce undesirable results, as the following attempt to perform a case-insensitive comparison of the strings "file" and "FILE" illustrates.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string fileUrl = "file";
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                       fileUrl.StartsWith("FILE", true, null));
      Console.WriteLine();
      
      Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                        fileUrl.StartsWith("FILE", true, null));
   }
}
// The example displays the following output:
//       Culture = English (United States)
//       (file == FILE) = True
//       
//       Culture = Turkish (Turkey)
//       (file == FILE) = False
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim fileUrl = "file"
      Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                       fileUrl.StartsWith("FILE", True, Nothing))
      Console.WriteLine()
      
      Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                        fileUrl.StartsWith("FILE", True, Nothing))
   End Sub
End Module
' The example displays the following output:
'       Culture = English (United States)
'       (file == FILE) = True
'       
'       Culture = Turkish (Turkey)
'       (file == FILE) = False

この比較は、セキュリティが重要となる状況でカルチャが不注意に使用されると、次の例のような重大な問題を引き起こす可能性があります。This comparison could cause significant problems if the culture is inadvertently used in security-sensitive settings, as in the following example. IsFileURI("file:") などのメソッド呼び出しは、現在のカルチャが英語 (米国) の場合は true を返しますが、現在のカルチャがトルコ語の場合は false を返します。A method call such as IsFileURI("file:") returns true if the current culture is U.S. English, but false if the current culture is Turkish. したがって、"FILE:" で始まる URI へのアクセスを大文字と小文字の区別なくブロックするセキュリティ対策は、トルコ語のシステムでは攻略される可能性があります。Thus, on Turkish systems, someone could circumvent security measures that block access to case-insensitive URIs that begin with "FILE:".

public static bool IsFileURI(String path) 
{
   return path.StartsWith("FILE:", true, null);
}
Public Shared Function IsFileURI(path As String) As Boolean 
   Return path.StartsWith("FILE:", True, Nothing)
End Function

この例の "file:" は、カルチャに依存しない非言語的な識別子として解釈されるものなので、コードを次のように書き換える必要があります。In this case, because "file:" is meant to be interpreted as a non-linguistic, culture-insensitive identifier, the code should instead be written as shown in the following example.

public static bool IsFileURI(string path) 
{
   return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
}
Public Shared Function IsFileURI(path As String) As Boolean 
    Return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase)
End Function

序数に基づく文字列操作Ordinal String Operations

メソッド呼び出しで StringComparison.Ordinal 値または StringComparison.OrdinalIgnoreCase 値を指定すると、非言語的な比較が行われ、自然言語の特性は無視されます。Specifying the StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase value in a method call signifies a non-linguistic comparison in which the features of natural languages are ignored. これらの StringComparison 値を使用して呼び出されたメソッドでは、文字列操作の判断が、大文字と小文字の指定、またはカルチャでパラメーター化される同等の表ではなく、単純なバイト比較に基づいて行われます。Methods that are invoked with these StringComparison values base string operation decisions on simple byte comparisons instead of casing or equivalence tables that are parameterized by culture. これにより、ほとんどの場合に文字列が意図されたとおりに解釈され、コードの実行速度と信頼性も向上します。In most cases, this approach best fits the intended interpretation of strings while making code faster and more reliable.

序数に基づく比較とは、各文字列の各バイトが言語的に解釈されずに比較される文字列比較です (たとえば、"windows" と "Windows" は一致しません)。Ordinal comparisons are string comparisons in which each byte of each string is compared without linguistic interpretation; for example, "windows" does not match "Windows". これは、実質的には C ランタイムの strcmp 関数の呼び出しです。This is essentially a call to the C runtime strcmp function. 文字列が厳密に一致する必要がある状況や、慎重な照合ポリシーが求められる状況では、この比較を使用します。Use this comparison when the context dictates that strings should be matched exactly or demands conservative matching policy. また、序数に基づく比較は最も高速な比較演算でもあります。これは、結果を判定するときに言語の規則が適用されないためです。Additionally, ordinal comparison is the fastest comparison operation because it applies no linguistic rules when determining a result.

.NET の文字列には、null 文字が埋め込まれる場合があります。Strings in .NET can contain embedded null characters. 序数に基づく比較とカルチャに依存した比較 (インバリアント カルチャを使用する比較を含む) の最も明白な違いの 1 つは、文字列に埋め込まれた null 文字の処理に関連しています。One of the clearest differences between ordinal and culture-sensitive comparison (including comparisons that use the invariant culture) concerns the handling of embedded null characters in a string. これらの文字は、String.Compare メソッドや String.Equals メソッドを使用して、カルチャに依存した比較 (インバリアント カルチャを使用する比較を含む) を実行する場合には無視されます。These characters are ignored when you use the String.Compare and String.Equals methods to perform culture-sensitive comparisons (including comparisons that use the invariant culture). その結果、カルチャに依存した比較では、null 文字が埋め込まれた文字列と null 文字が埋め込まれていない文字列が等価と見なされる可能性があります。As a result, in culture-sensitive comparisons, strings that contain embedded null characters can be considered equal to strings that do not.

重要

埋め込まれた null 文字は、文字列比較メソッドでは無視されますが、文字列検索メソッド (String.ContainsString.EndsWithString.IndexOfString.LastIndexOfString.StartsWith など) では無視されません。Although string comparison methods disregard embedded null characters, string search methods such as String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOf, and String.StartsWith do not.

次の例では、文字列 "Aa" と、"A" と "a" の間にいくつかの null 文字が埋め込まれた類似の文字列とのカルチャに依存した比較を実行して、2 つの文字列が等価と見なされることを示しています。The following example performs a culture-sensitive comparison of the string "Aa" with a similar string that contains several embedded null characters between "A" and "a", and shows how the two strings are considered equal.

using System;

public class Example
{
   public static void Main()
   {
      string str1 = "Aa";
      string str2 = "A" + new String('\u0000', 3) + "a";
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                        str1, ShowBytes(str1), str2, ShowBytes(str2));
      Console.WriteLine("   With String.Compare:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.InvariantCulture));

      Console.WriteLine("   With String.Equals:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.InvariantCulture));
   }
   
   private static string ShowBytes(string str)
   {
      string hexString = String.Empty;
      for (int ctr = 0; ctr < str.Length; ctr++)
      {
         string result = String.Empty;
         result = Convert.ToInt32(str[ctr]).ToString("X4");
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2);
         hexString += result;
      }
      return hexString.Trim();
   }
}
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Current Culture: 0
//          Invariant Culture: 0
//       With String.Equals:
//          Current Culture: True
//          Invariant Culture: True
Module Example
   Public Sub Main()
      Dim str1 As String = "Aa"
      Dim str2 As String = "A" + New String(Convert.ToChar(0), 3) + "a"
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                        str1, ShowBytes(str1), str2, ShowBytes(str2))
      Console.WriteLine("   With String.Compare:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.InvariantCulture))

      Console.WriteLine("   With String.Equals:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.InvariantCulture))
   End Sub
   
   Private Function ShowBytes(str As String) As String
      Dim hexString As String = String.Empty
      For ctr As Integer = 0 To str.Length - 1
         Dim result As String = String.Empty
         result = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2)
         hexString += result
      Next
      Return hexString.Trim()
   End Function
End Module

一方、次の例のように序数に基づく比較を使用すると、これらの文字列は等価とは見なされません。However, the strings are not considered equal when you use ordinal comparison, as the following example shows.

Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                  str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine("   With String.Compare:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Compare(str1, str2, StringComparison.Ordinal));

Console.WriteLine("   With String.Equals:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Equals(str1, str2, StringComparison.Ordinal));
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Ordinal: 97
//       With String.Equals:
//          Ordinal: False
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                  str1, ShowBytes(str1), str2, ShowBytes(str2))
Console.WriteLine("   With String.Compare:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Compare(str1, str2, StringComparison.Ordinal))

Console.WriteLine("   With String.Equals:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Equals(str1, str2, StringComparison.Ordinal))
' The example displays the following output:
'    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
'       With String.Compare:
'          Ordinal: 97
'       With String.Equals:
'          Ordinal: False

その次に慎重な方法は、大文字と小文字を区別しない序数に基づく比較です。Case-insensitive ordinal comparisons are the next most conservative approach. この比較では、大文字と小文字の区別のほとんどが無視されます (たとえば、"windows" と "Windows" は一致します)。These comparisons ignore most casing; for example, "windows" matches "Windows". ASCII 文字を操作する場合、このポリシーは StringComparison.Ordinal と同等ですが、通常の ASCII の大文字と小文字の区別が無視されます。When dealing with ASCII characters, this policy is equivalent to StringComparison.Ordinal, except that it ignores the usual ASCII casing. したがって、[A, Z] (\u0041-\u005A) の任意の文字が [a,z] (\u0061-\007A) の対応する文字と一致します。Therefore, any character in [A, Z] (\u0041-\u005A) matches the corresponding character in [a,z] (\u0061-\007A). ASCII の範囲外の大文字と小文字の区別には、インバリアント カルチャのテーブルが使用されます。Casing outside the ASCII range uses the invariant culture's tables. 次に例を示します。Therefore, the following comparison:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)

この比較は、次の比較と同等です (ただし、より高速です)。is equivalent to (but faster than) this comparison:

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal);
String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal)

とはいえ、これらの比較はどちらも非常に高速です。These comparisons are still very fast.

注意

ファイル システム、レジストリのキーと値、および環境変数の文字列の動作は、StringComparison.OrdinalIgnoreCase によって最もよく表現されます。The string behavior of the file system, registry keys and values, and environment variables is best represented by StringComparison.OrdinalIgnoreCase.

StringComparison.OrdinalStringComparison.OrdinalIgnoreCase は、どちらもバイナリ値を直接使用するため、照合に最適です。Both StringComparison.Ordinal and StringComparison.OrdinalIgnoreCase use the binary values directly, and are best suited for matching. 比較の設定について確信を持てない場合は、この 2 つのいずれかの値を使用してください。When you are not sure about your comparison settings, use one of these two values. ただし、これらの値を使用するとバイトごとの比較が行われるため、言語的な順序 (英語の辞書のような順序) ではなくバイナリの順序で並べ替えが行われます。However, because they perform a byte-by-byte comparison, they do not sort by a linguistic sort order (like an English dictionary) but by a binary sort order. したがって、結果をユーザーに表示すると、ほとんどの場合不自然に見えます。The results may look odd in most contexts if displayed to users.

序数に基づくセマンティクスは、StringComparison 引数を含まない String.Equals のオーバーロード (等値演算子を含む) で既定で使用されます。Ordinal semantics are the default for String.Equals overloads that do not include a StringComparison argument (including the equality operator). どのような場合でも、 StringComparison パラメーターを持つオーバーロードを呼び出すことをお勧めします。In any case, we recommend that you call an overload that has a StringComparison parameter.

インバリアント カルチャを使用する文字列操作String Operations that Use the Invariant Culture

インバリアント カルチャを使用する比較では、静的 CultureInfo.InvariantCulture プロパティから返される CompareInfo プロパティが使用されます。Comparisons with the invariant culture use the CompareInfo property returned by the static CultureInfo.InvariantCulture property. この動作は、すべてのシステムで同じです。範囲外の文字は、等価のインバリアント文字と見なされる文字に変換されます。This behavior is the same on all systems; it translates any characters outside its range into what it believes are equivalent invariant characters. このポリシーは、同じ文字列動作のセットを複数のカルチャにわたって保持する場合に便利ですが、予期しない結果になることもよくあります。This policy can be useful for maintaining one set of string behavior across cultures, but it often provides unexpected results.

インバリアント カルチャを使用する、大文字と小文字を区別しない比較でも、静的 CultureInfo.InvariantCulture プロパティから返される静的 CompareInfo プロパティが比較情報として使用されます。Case-insensitive comparisons with the invariant culture use the static CompareInfo property returned by the static CultureInfo.InvariantCulture property for comparison information as well. 変換後の文字の大文字と小文字の違いは無視されます。Any case differences among these translated characters are ignored.

StringComparison.InvariantCulture を使用する比較と StringComparison.Ordinal を使用する比較は、ASCII 文字列に対して同じように動作します。Comparisons that use StringComparison.InvariantCulture and StringComparison.Ordinal work identically on ASCII strings. ただし、StringComparison.InvariantCulture では言語的な判断が下されるため、バイト セットとして解釈する必要がある文字列に対しては不適切になることがあります。However, StringComparison.InvariantCulture makes linguistic decisions that might not be appropriate for strings that have to be interpreted as a set of bytes. CultureInfo.InvariantCulture.CompareInfo オブジェクトのために Compare メソッドで特定の文字のセットが等価と解釈されることもあります。The CultureInfo.InvariantCulture.CompareInfo object makes the Compare method interpret certain sets of characters as equivalent. たとえば、次の例が等価になるのは、インバリアント カルチャでは妥当です。For example, the following equivalence is valid under the invariant culture:

InvariantCulture: a + ̊ = åInvariantCulture: a + ̊ = å

LATIN SMALL LETTER A 文字 "a" (\u0061) は、COMBINING RING ABOVE 文字 "+ " ̊" (\u030a) の横にある場合、LATIN SMALL LETTER A WITH RING ABOVE 文字 "å" (\u00e5) として解釈されます。The LATIN SMALL LETTER A character "a" (\u0061), when it is next to the COMBINING RING ABOVE character "+ " ̊" (\u030a), is interpreted as the LATIN SMALL LETTER A WITH RING ABOVE character "å" (\u00e5). この動作は、次の例に示すように、序数に基づく比較とは異なります。As the following example shows, this behavior differs from ordinal comparison.

string separated = "\u0061\u030a";
string combined = "\u00e5";
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",
                  separated, combined, 
                  String.Compare(separated, combined, 
                                 StringComparison.InvariantCulture) == 0);

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",
                  separated, combined,
                  String.Compare(separated, combined, 
                                 StringComparison.Ordinal) == 0);
// The example displays the following output:
//    Equal sort weight of a° and å using InvariantCulture: True
//    Equal sort weight of a° and å using Ordinal: False      
Dim separated As String = ChrW(&h61) + ChrW(&h30a)
Dim combined As String = ChrW(&he5)
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _ 
                                 StringComparison.InvariantCulture) = 0)

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _
                                 StringComparison.Ordinal) = 0)
' The example displays the following output:
'    Equal sort weight of a° and å using InvariantCulture: True
'    Equal sort weight of a° and å using Ordinal: False

ファイル名やクッキーなど、"å" のような組み合わせが出現する可能性がある要素を解釈する場合にも、序数に基づく比較を使用するのが最も明確かつ適切な方法になります。When interpreting file names, cookies, or anything else where a combination such as "å" can appear, ordinal comparisons still offer the most transparent and fitting behavior.

結局のところ、インバリアント カルチャには、比較に使用する際に便利なプロパティがほとんどありません。On balance, the invariant culture has very few properties that make it useful for comparison. インバリアント カルチャを使用すると、言語的な意味を持つ形で比較が行われるため、記号の完全な等価性は保証されません。その一方で、特定のカルチャでの表示にも適していません。It does comparison in a linguistically relevant manner, which prevents it from guaranteeing full symbolic equivalence, but it is not the choice for display in any culture. StringComparison.InvariantCulture を比較に使用する数少ない理由の 1 つは、順序付けされたデータを複数のカルチャで同じように表示するために永続化できることです。One of the few reasons to use StringComparison.InvariantCulture for comparison is to persist ordered data for a cross-culturally identical display. たとえば、表示する並べ替え済みの識別子のリストを含む大きなデータ ファイルがアプリケーションに付属している場合に、そのリストにエントリを追加するには、インバリアント スタイルの並べ替えを使用する挿入が必要になります。For example, if a large data file that contains a list of sorted identifiers for display accompanies an application, adding to this list would require an insertion with invariant-style sorting.

ページのトップへBack to top

メソッド呼び出しに使用する StringComparison メンバーの選択Choosing a StringComparison Member for Your Method Call

文字列のセマンティックなコンテキストと StringComparison 列挙型のメンバーとの対応関係の概要を次の表に示します。The following table outlines the mapping from semantic string context to a StringComparison enumeration member.

データData 動作Behavior 対応する System.StringComparisonCorresponding System.StringComparison

value
大文字と小文字が区別される内部識別子。Case-sensitive internal identifiers.

XML や HTTP などの標準の、大文字と小文字が区別される識別子。Case-sensitive identifiers in standards such as XML and HTTP.

大文字と小文字が区別されるセキュリティ関連の設定。Case-sensitive security-related settings.
バイトが正確に一致する非言語的識別子。A non-linguistic identifier, where bytes match exactly. Ordinal
大文字と小文字が区別されない内部識別子。Case-insensitive internal identifiers.

XML や HTTP などの標準の、大文字と小文字が区別されない識別子。Case-insensitive identifiers in standards such as XML and HTTP.

ファイル パス。File paths.

レジストリのキーと値。Registry keys and values.

環境変数。Environment variables.

リソース識別子 (ハンドル名など)。Resource identifiers (for example, handle names).

大文字と小文字が区別されないセキュリティ関連の設定。Case-insensitive security-related settings.
大文字と小文字が区別されない、言語的な意味を持たない識別子 (ほとんどの Windows システム サービスで格納されるデータなど)。A non-linguistic identifier, where case is irrelevant; especially data stored in most Windows system services. OrdinalIgnoreCase
永続化される、言語的な意味を持つデータの一部。Some persisted, linguistically relevant data.

一定の並べ替え順序を必要とする言語的なデータの表示。Display of linguistic data that requires a fixed sort order.
カルチャに依存しないが、言語的な意味を持つデータ。Culturally agnostic data that still is linguistically relevant. InvariantCulture

- または --or-

InvariantCultureIgnoreCase
ユーザーに表示されるデータ。Data displayed to the user.

ほとんどのユーザー入力。Most user input.
特定の言語の規則を必要とするデータ。Data that requires local linguistic customs. CurrentCulture

- または --or-

CurrentCultureIgnoreCase

ページのトップへBack to top

.NET の一般的な文字列比較メソッドCommon String Comparison Methods in .NET

以降では、文字列比較でよく使用されるメソッドについて説明します。The following sections describe the methods that are most commonly used for string comparison.

String.CompareString.Compare

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

このメソッドは文字列解釈の中心的な操作となるため、メソッド呼び出しのすべてのインスタンスを調べて、文字列を現在のカルチャに従って解釈するべきか、カルチャから切り離して (記号として) 扱うべきかどうかを確認する必要があります。As the operation most central to string interpretation, all instances of these method calls should be examined to determine whether strings should be interpreted according to the current culture, or dissociated from the culture (symbolically). ほとんどは後者であるため、その場合は代わりに StringComparison.Ordinal の比較を使用します。Typically, it is the latter, and a StringComparison.Ordinal comparison should be used instead.

CultureInfo.CompareInfo プロパティから返される System.Globalization.CompareInfo クラスにも、CompareOptions フラグ列挙体でさまざまな照合方法 (序数に基づく、空白文字を無視する、カナ型を無視するなど) を指定できる Compare メソッドが含まれています。The System.Globalization.CompareInfo class, which is returned by the CultureInfo.CompareInfo property, also includes a Compare method that provides a large number of matching options (ordinal, ignoring white space, ignoring kana type, and so on) by means of the CompareOptions flag enumeration.

String.CompareToString.CompareTo

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

このメソッドには、現時点では、StringComparison 型を指定するオーバーロードはありません。This method does not currently offer an overload that specifies a StringComparison type. 通常は、このメソッドを推奨される String.Compare(String, String, StringComparison) の形式に変換できます。It is usually possible to convert this method to the recommended String.Compare(String, String, StringComparison) form.

このメソッドは、 IComparable インターフェイスと IComparable<T> インターフェイスを実装する型に実装されます。Types that implement the IComparable and IComparable<T> interfaces implement this method. このメソッドには StringComparison パラメーターのオプションがないため、実装する型のコンストラクターで StringComparer を指定できるようにするのが一般的です。Because it does not offer the option of a StringComparison parameter, implementing types often let the user specify a StringComparer in their constructor. 次の例では、クラス コンストラクターに StringComparer パラメーターを含む FileName クラスを定義しています。The following example defines a FileName class whose class constructor includes a StringComparer parameter. この StringComparer オブジェクトは、その後、 FileName.CompareTo メソッドで使用されています。This StringComparer object is then used in the FileName.CompareTo method.

using System;

public class FileName : IComparable
{
   string fname;
   StringComparer comparer; 
   
   public FileName(string name, StringComparer comparer)
   {
      if (String.IsNullOrEmpty(name))
         throw new ArgumentNullException("name");

      this.fname = name;
      
      if (comparer != null)
         this.comparer = comparer;
      else
         this.comparer = StringComparer.OrdinalIgnoreCase;
   }

   public string Name
   {
      get { return fname; }
   }
   
   public int CompareTo(object obj)
   {
      if (obj == null) return 1;

      if (! (obj is FileName))
         return comparer.Compare(this.fname, obj.ToString());
      else
         return comparer.Compare(this.fname, ((FileName) obj).Name);
   }
}
Public Class FileName : Implements IComparable
   Dim fname As String
   Dim comparer As StringComparer 
   
   Public Sub New(name As String, comparer As StringComparer)
      If String.IsNullOrEmpty(name) Then
         Throw New ArgumentNullException("name")
      End If

      Me.fname = name
      
      If comparer IsNot Nothing Then
         Me.comparer = comparer
      Else
         Me.comparer = StringComparer.OrdinalIgnoreCase
      End If      
   End Sub

   Public ReadOnly Property Name As String
      Get
         Return fname
      End Get   
   End Property
   
   Public Function CompareTo(obj As Object) As Integer _
          Implements IComparable.CompareTo
      If obj Is Nothing Then Return 1

      If Not TypeOf obj Is FileName Then
         obj = obj.ToString()
      Else
         obj = CType(obj, FileName).Name
      End If         
      Return comparer.Compare(Me.fname, obj)
   End Function
End Class

String.EqualsString.Equals

既定の解釈: StringComparison.OrdinalDefault interpretation: StringComparison.Ordinal.

String クラスで等価性テストを実行するには、 Equals メソッド (静的メソッドまたはインスタンス メソッド) のオーバーロードを呼び出すか、静的等値演算子を使用します。The String class lets you test for equality by calling either the static or instance Equals method overloads, or by using the static equality operator. これらのオーバーロードと演算子では、序数に基づく比較が既定で使用されます。The overloads and operator use ordinal comparison by default. しかし、序数に基づく比較を実行する場合でも、StringComparison 型を明示的に指定するオーバーロードを呼び出すことをお勧めします。これにより、特定の文字列解釈のコードを検索しやすくなります。However, we still recommend that you call an overload that explicitly specifies the StringComparison type even if you want to perform an ordinal comparison; this makes it easier to search code for a certain string interpretation.

String.ToUpper と String.ToLowerString.ToUpper and String.ToLower

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

これらのメソッドを使用するときには注意が必要です。というのも、文字列を大文字や小文字に強制的に変換する操作は、文字列を大文字と小文字の区別に関係なく比較するための小規模の正規化としてよく使用されるからです。You should be careful when you use these methods, because forcing a string to a uppercase or lowercase is often used as a small normalization for comparing strings regardless of case. その場合は、大文字と小文字を区別しない比較を使用することを検討してください。If so, consider using a case-insensitive comparison.

String.ToUpperInvariant メソッドと String.ToLowerInvariant メソッドを使用することもできます。The String.ToUpperInvariant and String.ToLowerInvariant methods are also available. ToUpperInvariant は、大文字と小文字を正規化するための標準的な方法です。ToUpperInvariant is the standard way to normalize case. StringComparison.OrdinalIgnoreCase を使用して行われる比較は、動作の内容を見ると、両方の文字列引数に対して ToUpperInvariant を呼び出し、StringComparison.Ordinal を使用して比較を行うという、2 つの呼び出しの組み合わせです。Comparisons made using StringComparison.OrdinalIgnoreCase are behaviorally the composition of two calls: calling ToUpperInvariant on both string arguments, and doing a comparison using StringComparison.Ordinal.

特定のカルチャを表す CultureInfo オブジェクトをメソッドに渡して、そのカルチャで大文字および小文字への変換を行うためのオーバーロードもあります。Overloads are also available for converting to uppercase and lowercase in a specific culture, by passing a CultureInfo object that represents that culture to the method.

Char.ToUpper と Char.ToLowerChar.ToUpper and Char.ToLower

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

これらのメソッドの動作は、上で説明した String.ToUpper メソッドおよび String.ToLower メソッドと同様です。These methods work similarly to the String.ToUpper and String.ToLower methods described in the previous section.

String.StartsWith と String.EndsWithString.StartsWith and String.EndsWith

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

これらのメソッドは、いずれもカルチャに依存した比較を既定で実行します。By default, both of these methods perform a culture-sensitive comparison.

String.IndexOf と String.LastIndexOfString.IndexOf and String.LastIndexOf

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

これらのメソッドの既定のオーバーロードは、比較の実行方法が一貫していません。There is a lack of consistency in how the default overloads of these methods perform comparisons. Char パラメーターを含むすべての String.IndexOf メソッドと String.LastIndexOf メソッドは、序数に基づく比較を実行します。一方、String パラメーターを含む既定の String.IndexOf メソッドと String.LastIndexOf メソッドは、カルチャに依存した比較を実行します。All String.IndexOf and String.LastIndexOf methods that include a Char parameter perform an ordinal comparison, but the default String.IndexOf and String.LastIndexOf methods that include a String parameter perform a culture-sensitive comparison.

String.IndexOf(String) メソッドまたは String.LastIndexOf(String) メソッドを呼び出して、現在のインスタンスで検索する文字列を渡す場合は、StringComparison 型を明示的に指定するオーバーロードを呼び出すことをお勧めします。If you call the String.IndexOf(String) or String.LastIndexOf(String) method and pass it a string to locate in the current instance, we recommend that you call an overload that explicitly specifies the StringComparison type. Char 引数を含むオーバーロードでは、 StringComparison 型を指定することはできません。The overloads that include a Char argument do not allow you to specify a StringComparison type.

ページのトップへBack to top

間接的に文字列比較を実行するメソッドMethods that Perform String Comparison Indirectly

文字列比較を中心的な操作とする非文字列メソッドの中には、 StringComparer 型を使用するものがあります。Some non-string methods that have string comparison as a central operation use the StringComparer type. StringComparer クラスには、StringComparer のインスタンスを返す静的プロパティが 6 つ含まれています。これらのインスタンスの StringComparer.Compare メソッドは、次の種類の文字列比較を実行します。The StringComparer class includes six static properties that return StringComparer instances whose StringComparer.Compare methods perform the following types of string comparisons:

Array.Sort と Array.BinarySearchArray.Sort and Array.BinarySearch

既定の解釈: StringComparison.CurrentCultureDefault interpretation: StringComparison.CurrentCulture.

データをコレクションに格納したり、永続化されたデータをファイルやデータベースからコレクションに読み取ったりするときに現在のカルチャを切り替えると、コレクション内のインバリアントが無効になる可能性があります。When you store any data in a collection, or read persisted data from a file or database into a collection, switching the current culture can invalidate the invariants in the collection. Array.BinarySearch メソッドでは、配列内で検索する要素が既に並べ替えられていると見なされます。The Array.BinarySearch method assumes that the elements in the array to be searched are already sorted. Array.Sort メソッドは、配列内の文字列要素を並べ替えるために、String.Compare メソッドを呼び出して個々の要素を順序付けます。To sort any string element in the array, the Array.Sort method calls the String.Compare method to order individual elements. 配列の並べ替えが行われてから内容の検索が行われるまでの間にカルチャが変更される場合、カルチャに依存した比較子を使用するのは危険です。Using a culture-sensitive comparer can be dangerous if the culture changes between the time that the array is sorted and its contents are searched. たとえば、次のコードでは、Thread.CurrentThread.CurrentCulture プロパティが暗黙的に指定した比較子で格納と取得の操作が行われます。For example, in the following code, storage and retrieval operate on the comparer that is provided implicitly by the Thread.CurrentThread.CurrentCulture property. StoreNames の呼び出しと DoesNameExistの呼び出しの間にカルチャが変更されると (この 2 つのメソッドの呼び出しの間に配列の内容が永続化された場合には特に)、バイナリ サーチが失敗する可能性があります。If the culture can change between the calls to StoreNames and DoesNameExist, and especially if the array contents are persisted somewhere between the two method calls, the binary search may fail.

// Incorrect.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names); // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name) >= 0);  // Line B.
}
' Incorrect.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names)          ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name) >= 0      ' Line B.
End Function

次の例は、推奨されるバリエーションを示しています。ここでは、配列の並べ替えと検索の両方に、同じ序数に基づく (カルチャに依存しない) 比較メソッドが使用されています。A recommended variation appears in the following example, which uses the same ordinal (culture-insensitive) comparison method both to sort and to search the array. コードの変更は、2 つの例の Line A および Line B というラベルが付いた行に反映されています。The change code is reflected in the lines labeled Line A and Line B in the two examples.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.Ordinal);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.Ordinal)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.Ordinal) >= 0      ' Line B.
End Function

このデータを永続化して別のカルチャのシステムに移動したり、データをユーザーに表示するために並べ替えたりする場合は、StringComparison.InvariantCulture を使用することを検討してください。そうすると、ユーザー出力のために言語的な操作を行っても、カルチャの変更による影響を受けることはありません。If this data is persisted and moved across cultures, and sorting is used to present this data to the user, you might consider using StringComparison.InvariantCulture, which operates linguistically for better user output but is unaffected by changes in culture. 次の例では、前の 2 つの例を変更して、配列の並べ替えと検索にインバリアント カルチャを使用しています。The following example modifies the two previous examples to use the invariant culture for sorting and searching the array.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.InvariantCulture);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.InvariantCulture)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.InvariantCulture) >= 0      ' Line B.
End Function

コレクションの例: Hashtable のコンストラクターCollections Example: Hashtable Constructor

文字列の比較方法の影響を受ける操作の 2 例目は文字列のハッシュです。Hashing strings provides a second example of an operation that is affected by the way in which strings are compared.

次の例では、StringComparer.OrdinalIgnoreCase プロパティから返される StringComparer オブジェクトを渡して Hashtable オブジェクトをインスタンス化しています。The following example instantiates a Hashtable object by passing it the StringComparer object that is returned by the StringComparer.OrdinalIgnoreCase property. StringComparer から派生するクラス StringComparerIEqualityComparer インターフェイスを実装するため、その GetHashCode メソッドを使用して、ハッシュ テーブルの文字列のハッシュ コードを計算しています。Because a class StringComparer that is derived from StringComparer implements the IEqualityComparer interface, its GetHashCode method is used to compute the hash code of strings in the hash table.

const int initialTableCapacity = 100;
Hashtable h;

public void PopulateFileTable(string directory)
{
   h = new Hashtable(initialTableCapacity, 
                     StringComparer.OrdinalIgnoreCase);
         
   foreach (string file in Directory.GetFiles(directory))
         h.Add(file, File.GetCreationTime(file));
}

public void PrintCreationTime(string targetFile)
{
   Object dt = h[targetFile];
   if (dt != null)
   {
      Console.WriteLine("File {0} was created at time {1}.",
         targetFile, 
         (DateTime) dt);
   }
   else
   {
      Console.WriteLine("File {0} does not exist.", targetFile);
   }
}
Const initialTableCapacity As Integer = 100
Dim h As Hashtable

Public Sub PopulateFileTable(dir As String)
   h = New Hashtable(initialTableCapacity, _
                     StringComparer.OrdinalIgnoreCase)
                     
   For Each filename As String In Directory.GetFiles(dir)
      h.Add(filename, File.GetCreationTime(filename))
   Next                        
End Sub

Public Sub PrintCreationTime(targetFile As String)
   Dim dt As Object = h(targetFile)
   If dt IsNot Nothing Then
      Console.WriteLine("File {0} was created at {1}.", _
         targetFile, _
         CDate(dt))
   Else
      Console.WriteLine("File {0} does not exist.", targetFile)
   End If
End Sub  

ページのトップへBack to top

書式設定されたデータを表示および保持するDisplaying and Persisting Formatted Data

数値、日時など、文字列以外のデータをユーザーに表示するには、ユーザーのカルチャ設定を使用して書式設定します。When you display non-string data such as numbers and dates and times to users, format them by using the user's cultural settings. 既定では、数値型と日時型の String.Format メソッドと ToString メソッドは、書式設定の操作に現在のスレッド カルチャを使用します。By default, the String.Format method and the ToString methods of the numeric types and the date and time types use the current thread culture for formatting operations. 書式指定メソッドで現在のカルチャを使用することを明示的に指定するには、provider パラメーターを含む書式指定メソッド (String.Format(IFormatProvider, String, Object[])DateTime.ToString(IFormatProvider) など) のオーバーロードを呼び出し、そのパラメーターを CultureInfo.CurrentCulture プロパティに渡すことができます。To explicitly specify that the formatting method should use the current culture, you can call an overload of a formatting method that has a provider parameter, such as String.Format(IFormatProvider, String, Object[]) or DateTime.ToString(IFormatProvider), and pass it the CultureInfo.CurrentCulture property.

文字列以外のデータは、バイナリ データまたは書式付きデータとして保持できます。You can persist non-string data either as binary data or as formatted data. 書式付きデータとして保存するには、provider パラメーターを含む書式指定メソッドのオーバーロードを呼び出し、そのパラメーターを CultureInfo.InvariantCulture プロパティに渡す必要があります。If you choose to save it as formatted data, you should call a formatting method overload that includes a provider parameter and pass it the CultureInfo.InvariantCulture property. インバリアント カルチャは、カルチャとコンピューターに依存しない書式付きデータに一貫した書式を提供します。The invariant culture provides a consistent format for formatted data that is independent of culture and machine. これに対し、インバリアント カルチャ以外のカルチャを使用して書式設定するデータの保持には、さまざまな制限があります。In contrast, persisting data that is formatted by using cultures other than the invariant culture has a number of limitations:

  • カルチャが異なるシステムでデータを取得したり、現在のシステムのユーザーが現在のカルチャを変更してデータを取得しようとしたりすると、そのデータは使用できない可能性があります。The data is likely to be unusable if it is retrieved on a system that has a different culture, or if the user of the current system changes the current culture and tries to retrieve the data.

  • 特定のコンピューターのカルチャのプロパティは、その標準の値とは異なる場合があります。The properties of a culture on a specific computer can differ from standard values. 常に、ユーザーはカルチャに依存した表示設定をカスタマイズする可能性があります。At any time, a user can customize culture-sensitive display settings. このため、ユーザーがカルチャの設定をカスタマイズすると、システムに保存されている書式付きデータを読み取ることができなくなる場合があります。Because of this, formatted data that is saved on a system may not be readable after the user customizes cultural settings. コンピューター間の書式付きデータの移植性がさらに制限される可能性があります。The portability of formatted data across computers is likely to be even more limited.

  • 数値や日時の書式設定を制御する国際的、地域的、または国内の標準は時間と共に変化するため、これらの変化は Windows オペレーティング システムの更新プログラムに組み込まれています。International, regional, or national standards that govern the formatting of numbers or dates and times change over time, and these changes are incorporated into Windows operating system updates. 書式設定の規則が変わると、以前の規則に従って書式設定されたデータを読み取ることができなくなる場合があります。When formatting conventions change, data that was formatted by using the previous conventions may become unreadable.

次に、カルチャに依存する書式設定を使用してデータを保持すると移植性が制限される例を示します。The following example illustrates the limited portability that results from using culture-sensitive formatting to persist data. この例では、日時の値の配列をファイルに保存します。The example saves an array of date and time values to a file. これらは、英語 (米国) のカルチャの規則を使用して書式設定されています。These are formatted by using the conventions of the English (United States) culture. 現在のスレッド カルチャがフランス語 (スイス) に変更されると、アプリケーションは現在のカルチャの書式設定規則を使用して保存された値を読み取ることを試みます。After the application changes the current thread culture to French (Switzerland), it tries to read the saved values by using the formatting conventions of the current culture. 2 つのデータ項目の読み取りを試みると、FormatException 例外がスローされます。日付の配列には、MinValue に等しい 2 つの間違った要素が含まれることになります。The attempt to read two of the data items throws a FormatException exception, and the array of dates now contains two incorrect elements that are equal to MinValue.

using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;

public class Example
{
   private static string filename = @".\dates.dat";

   public static void Main()
   {
      DateTime[] dates = { new DateTime(1758, 5, 6, 21, 26, 0), 
                           new DateTime(1818, 5, 5, 7, 19, 0), 
                           new DateTime(1870, 4, 22, 23, 54, 0),  
                           new DateTime(1890, 9, 8, 6, 47, 0), 
                           new DateTime(1905, 2, 18, 15, 12, 0) }; 
      // Write the data to a file using the current culture.
      WriteData(dates);
      // Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH");
      // Read the data using the current culture.
      DateTime[] newDates = ReadData();
      foreach (var newDate in newDates)
         Console.WriteLine(newDate.ToString("g"));
   }
   
   private static void WriteData(DateTime[] dates) 
   {
      StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8);    
      for (int ctr = 0; ctr < dates.Length; ctr++) {
         sw.Write("{0}", dates[ctr].ToString("g", CultureInfo.CurrentCulture));
         if (ctr < dates.Length - 1) sw.Write("|");   
      }      
      sw.Close();
   }
   
   private static DateTime[] ReadData() 
   {
      bool exceptionOccurred = false;
           
      // Read file contents as a single string, then split it.
      StreamReader sr = new StreamReader(filename, Encoding.UTF8);
      string output = sr.ReadToEnd();
      sr.Close();   

      string[] values = output.Split( new char[] { '|' } );
      DateTime[] newDates = new DateTime[values.Length]; 
      for (int ctr = 0; ctr < values.Length; ctr++) {
         try {
            newDates[ctr] = DateTime.Parse(values[ctr], CultureInfo.CurrentCulture);
         }
         catch (FormatException) {
            Console.WriteLine("Failed to parse {0}", values[ctr]);
            exceptionOccurred = true;
         }
      }      
      if (exceptionOccurred) Console.WriteLine();
      return newDates;
   }
}
// The example displays the following output:
//       Failed to parse 4/22/1870 11:54 PM
//       Failed to parse 2/18/1905 3:12 PM
//       
//       05.06.1758 21:26
//       05.05.1818 07:19
//       01.01.0001 00:00
//       09.08.1890 06:47
//       01.01.0001 00:00
//       01.01.0001 00:00
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Threading

Module Example
   Private filename As String = ".\dates.dat"
   
   Public Sub Main()
      Dim dates() As Date = { #5/6/1758 9:26PM#, #5/5/1818 7:19AM#, _ 
                              #4/22/1870 11:54PM#, #9/8/1890 6:47AM#, _ 
                              #2/18/1905 3:12PM# }
      ' Write the data to a file using the current culture.
      WriteData(dates)
      ' Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH")
      ' Read the data using the current culture.
      Dim newDates() As Date = ReadData()
      For Each newDate In newDates
         Console.WriteLine(newDate.ToString("g"))
      Next
   End Sub
   
   Private Sub WriteData(dates() As Date)
      Dim sw As New StreamWriter(filename, False, Encoding.Utf8)    
      For ctr As Integer = 0 To dates.Length - 1
         sw.Write("{0}", dates(ctr).ToString("g", CultureInfo.CurrentCulture))
         If ctr < dates.Length - 1 Then sw.Write("|")   
      Next      
      sw.Close()
   End Sub
   
   Private Function ReadData() As Date()
      Dim exceptionOccurred As Boolean = False
           
      ' Read file contents as a single string, then split it.
      Dim sr As New StreamReader(filename, Encoding.Utf8)
      Dim output As String = sr.ReadToEnd()
      sr.Close()   

      Dim values() As String = output.Split( {"|"c } )
      Dim newDates(values.Length - 1) As Date 
      For ctr As Integer = 0 To values.Length - 1
         Try
            newDates(ctr) = DateTime.Parse(values(ctr), CultureInfo.CurrentCulture)
         Catch e As FormatException
            Console.WriteLine("Failed to parse {0}", values(ctr))
            exceptionOccurred = True
         End Try
      Next      
      If exceptionOccurred Then Console.WriteLine()
      Return newDates
   End Function
End Module
' The example displays the following output:
'       Failed to parse 4/22/1870 11:54 PM
'       Failed to parse 2/18/1905 3:12 PM
'       
'       05.06.1758 21:26
'       05.05.1818 07:19
'       01.01.0001 00:00
'       09.08.1890 06:47
'       01.01.0001 00:00
'       01.01.0001 00:00
'

しかし、CultureInfo.CurrentCulture プロパティを CultureInfo.InvariantCulture に置き換えて DateTime.ToString(String, IFormatProvider) 呼び出しと DateTime.Parse(String, IFormatProvider) 呼び出しを行うと、保持されている日時データは正常に復元されます。次にその出力を示します。However, if you replace the CultureInfo.CurrentCulture property with CultureInfo.InvariantCulture in the calls to DateTime.ToString(String, IFormatProvider) and DateTime.Parse(String, IFormatProvider), the persisted date and time data is successfully restored, as the following output shows.

06.05.1758 21:26  
05.05.1818 07:19  
22.04.1870 23:54  
08.09.1890 06:47  
18.02.1905 15:12  

関連項目See also