如何:在 C# 比較字串How to compare strings in C#

您可以比較字串來回答兩個問題的其中一個:「這兩個字串相等嗎?」You compare strings to answer one of two questions: "Are these two strings equal?" 或「這些字串在排序時應該以何種順序放置?」or "In what order should these strings be placed when sorting them?"

這兩個問題會因為影響字串比較的因素而變複雜:Those two questions are complicated by factors that affect string comparisons:

  • 您可以選擇序數或語言比較。You can choose an ordinal or linguistic comparison.
  • 您可以選擇大小寫是否重要。You can choose if case matters.
  • 您可以選擇文化特性 (Culture) 特定的比較。You can choose culture-specific comparisons.
  • 語言比較視文化特性 (Culture) 與平台而異。Linguistic comparisons are culture and platform-dependent.

注意

本文中的 C# 範例會在 Try.NET 內嵌程式碼執行器和測試區執行。The C# examples in this article run in the Try.NET inline code runner and playground. 選取 [執行] 按鈕以在互動式視窗中執行範例。Select the Run button to run an example in an interactive window. 執行程式碼之後,您便可以修改它,並再選取一次 [執行] 來執行修改過的程式碼。Once you execute the code, you can modify it and run the modified code by selecting Run again. 修改過的程式碼會在互動式視窗中執行,或是如果編譯失敗的話,互動式視窗會顯示所有 C# 編譯器錯誤訊息。The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C# compiler error messages.

當您比較字串時,您會定義它們之間的順序。When you compare strings, you define an order among them. 比較用來排序字串的序列。Comparisons are used to sort a sequence of strings. 一旦序列是已知的順序,軟體和人類都能比較容易搜尋。Once the sequence is in a known order, it is easier to search, both for software and for humans. 其他的比較可能會檢查字串是否相同。Other comparisons may check if strings are the same. 這些相同性檢查類似於相等,但可能會忽略部分差異,例如大小寫的差異。These sameness checks are similar to equality, but some differences, such as case differences, may be ignored.

預設的序數比較Default ordinal comparisons

最常見的作業:The most common operations:

使用序數比較、區分大小寫的比較,並使用目前文化特性。use an ordinal comparison, a case-sensitive comparison, and use the current culture. 下列範例將顯示結果:The results are shown in the following example:

string root = @"C:\users";
string root2 = @"C:\Users";

bool result = root.Equals(root2);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");

result = root.Equals(root2, StringComparison.Ordinal);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");

Console.WriteLine($"Using == says that <{root}> and <{root2}> are {(root == root2 ? "equal" : "not equal")}");               

比較字串時,預設序數比較不會考慮語言規則。The default ordinal comparison does not take linguistic rules into account when comparing strings. 其會在兩個字串中比較各 Char 物件的二進位值。It compares the binary value of each Char object in two strings. 如此一來,預設序數比較也會區分大小寫。As a result, the default ordinal comparison is also case-sensitive.

請注意,使用 String.EqualsString.Equality 測試是否相等與使用 String.CompareToCompare(String, String) 方法的字串比較不同。Note that the test for equality with String.Equals and String.Equality differs from string comparison using the String.CompareTo and Compare(String, String) methods. 當相等測試執行區分大小寫的序數比較時,比較方法會使用目前的文化特性 (Culture) 執行區分大小寫、區分文化的比較。While the tests for equality perform a case-sensitive ordinal comparison, the comparison method perform a case-sensitive, culture-sensitive comparison using the current culture. 因為預設比較方法時常執行不同類型的比較,所以建議您皆透過呼叫明確指定要執行比較之類型的多載,以讓程式碼的意圖更加明確。Because the default comparison methods often perform different types of comparisons, we recommend that you always make the intent of your code clear by calling an overload that explicitly specifies the type of comparison to perform.

不區分大小寫的序數比較Case-insensitive ordinal comparisons

String.Equals(String, StringComparison) 方法可讓您指定 StringComparisonStringComparison.OrdinalIgnoreCaseThe String.Equals(String, StringComparison) method enables you to specify a StringComparison value of StringComparison.OrdinalIgnoreCase 對於不區分大小寫的序數比較。for a case-insensitive ordinal comparison. 若為 StringComparison 引數指定 StringComparison.OrdinalIgnoreCase 的值,另外也有執行不區分大小寫序數比較的靜態 String.Compare(String, String, StringComparison) 方法。There is also a static String.Compare(String, String, StringComparison) method that performs a case-insensitive ordinal comparison if you specify a value of StringComparison.OrdinalIgnoreCase for the StringComparison argument. 如下列程式碼所示:These are shown in the following code:

string root = @"C:\users";
string root2 = @"C:\Users";

bool result = root.Equals(root2, StringComparison.OrdinalIgnoreCase);
bool areEqual = String.Equals(root, root2, StringComparison.OrdinalIgnoreCase);
int comparison = String.Compare(root, root2, comparisonType: StringComparison.OrdinalIgnoreCase);

Console.WriteLine($"Ordinal ignore case: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");
Console.WriteLine($"Ordinal static ignore case: <{root}> and <{root2}> are {(areEqual ? "equal." : "not equal.")}");
if (comparison < 0)
    Console.WriteLine($"<{root}> is less than <{root2}>");
else if (comparison > 0)
    Console.WriteLine($"<{root}> is greater than <{root2}>");
else
    Console.WriteLine($"<{root}> and <{root2}> are equivalent in order");

當執行區分大小寫的序數比較時,這些方法會使用不因文化特性而異的大小寫慣例。When performing a case-insensitive ordinal comparison, these methods use the casing conventions of the invariant culture.

語言比較Linguistic comparisons

字串也可以使用目前文化特性的語言規則來排序。Strings can also be ordered using linguistic rules for the current culture. 這有時候稱為「字組排序次序」。This is sometimes referred to as "word sort order." 當您執行語言比較時,部分非英數字元的 Unicode 字元可能會被指派特殊的權重。When you perform a linguistic comparison, some nonalphanumeric Unicode characters might have special weights assigned. 例如,連字號 "-" 可能會被指派很小的權重,以便 "co-op" 和 "coop" 在排序次序中會出現在彼此旁邊。For example, the hyphen "-" may have a very small weight assigned to it so that "co-op" and "coop" appear next to each other in sort order. 此外,某些 Unicode 字元可能會相等於 Char 執行個體的順序。In addition, some Unicode characters may be equivalent to a sequence of Char instances. 下列範例使用該片語 "They dance in the street"。The following example uses the phrase "They dance in the street." 以下使用德文「他們在街道上跳舞」為例,並在其中一個字串使用 "ss" (U+0073 U+0073),而另一個則使用 'ß' (U+00DF)。in German with the "ss" (U+0073 U+0073) in one string and 'ß' (U+00DF) in another. 在語言方面 (在 Windows 中),"ss" 等於 "en-US" 和 "de-DE" 文化特性中的德文 Esszet: 'ß' 字元。Linguistically (in Windows), "ss" is equal to the German Esszet: 'ß' character in both the "en-US" and "de-DE" cultures.

string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";

Console.WriteLine($"First sentence is <{first}>");
Console.WriteLine($"Second sentence is <{second}>");

bool equal = String.Equals(first, second, StringComparison.InvariantCulture);
Console.WriteLine($"The two strings {(equal == true ? "are" : "are not")} equal.");
showComparison(first, second);

string word = "coop";
string words = "co-op";
string other = "cop";

showComparison(word, words);
showComparison(word, other);
showComparison(words, other);
void showComparison(string one, string two)
{
    int compareLinguistic = String.Compare(one, two, StringComparison.InvariantCulture);
    int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
    if (compareLinguistic < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using invariant culture");
    else if (compareLinguistic > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using invariant culture");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using invariant culture");
    if (compareOrdinal < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
    else if (compareOrdinal > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}

這個範例會示範語言比較之作業系統相依的本質。This sample demonstrates the operating system-dependent nature of linguistic comparisons. 互動式視窗的主機是 Linux 主機。The host for the interactive window is a Linux host. 語言和序數比較會產生相同的結果。The linguistic and ordinal comparisons produce the same results. 如果您在 Windows 主機上執行相同的範例,您會看到下列輸出:If you ran this same sample on a Windows host, you would see the following output:

<coop> is less than <co-op> using invariant culture
<coop> is greater than <co-op> using ordinal comparison
<coop> is less than <cop> using invariant culture
<coop> is less than <cop> using ordinal comparison
<co-op> is less than <cop> using invariant culture
<co-op> is less than <cop> using ordinal comparison

在 Windows 上,"cop"、"coop" 和 "co-op" 的排序次序會在您從語言比較變更為序數比較時改變。On Windows, the sort order of "cop", "coop", and "co-op" change when you change from a linguistic comparison to an ordinal comparison. 兩個德文句子使用不同的比較型別時,比較起來也會不同。The two German sentences also compare differently using the different comparison types.

使用特定文化特性的比較Comparisons using specific cultures

此範例會儲存 en-US 及 de-DE 文化特性 (Culture) 的 CultureInfo 物件。This sample stores CultureInfo objects for the en-US and de-DE cultures. 比較是使用 CultureInfo 物件執行,以確保文化特性 (Culture) 特定的比較。The comparisons are performed using a CultureInfo object to ensure a culture-specific comparison.

使用的文化特性會影響語言比較。The culture used affects linguistic comparisons. 下列範例會顯示使用 "en-US" 文化特性和 "de-DE" 文化特性比較兩個德文句子的結果:The following example shows the results of comparing the two German sentences using the "en-US" culture and the "de-DE" culture:

string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";

Console.WriteLine($"First sentence is <{first}>");
Console.WriteLine($"Second sentence is <{second}>");

var en = new System.Globalization.CultureInfo("en-US");

// For culture-sensitive comparisons, use the String.Compare 
// overload that takes a StringComparison value.
int i = String.Compare(first, second, en, System.Globalization.CompareOptions.None);
Console.WriteLine($"Comparing in {en.Name} returns {i}.");

var de = new System.Globalization.CultureInfo("de-DE");
i = String.Compare(first, second, de, System.Globalization.CompareOptions.None);
Console.WriteLine($"Comparing in {de.Name} returns {i}.");

bool b = String.Equals(first, second, StringComparison.CurrentCulture);
Console.WriteLine($"The two strings {(b ? "are" : "are not")} equal.");

string word = "coop";
string words = "co-op";
string other = "cop";

showComparison(word, words, en);
showComparison(word, other, en);
showComparison(words, other, en);
void showComparison(string one, string two, System.Globalization.CultureInfo culture)
{
    int compareLinguistic = String.Compare(one, two, en, System.Globalization.CompareOptions.None);
    int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
    if (compareLinguistic < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using en-US culture");
    else if (compareLinguistic > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using en-US culture");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using en-US culture");
    if (compareOrdinal < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
    else if (compareOrdinal > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}

文化特性敏感的比較通常用來比較和排序使用者輸入的字串與使用者輸入的其他字串。Culture-sensitive comparisons are typically used to compare and sort strings input by users with other strings input by users. 這些字串的字元和排序慣例可能會視使用者電腦的地區設定而變。The characters and sorting conventions of these strings might vary depending on the locale of the user's computer. 即使包含完全相同字元的字串,也可能因目前執行緒的文化特性而改變排序。Even strings that contain identical characters might sort differently depending on the culture of the current thread. 此外,在 Windows 電腦上本機嘗試此範例程式碼,會產生下列結果:In addition, try this sample code locally on a Windows machine, and you will the following results:

<coop> is less than <co-op> using en-US culture
<coop> is greater than <co-op> using ordinal comparison
<coop> is less than <cop> using en-US culture
<coop> is less than <cop> using ordinal comparison
<co-op> is less than <cop> using en-US culture
<co-op> is less than <cop> using ordinal comparison

語言比較視目前的文化特性與 OS 而異。Linguistic comparisons are dependent on the current culture, and are OS dependent. 當您使用字串比較時必須考量此點。You must take that into account when you work with string comparisons.

陣列中的語言排序和字串搜尋Linguistic sorting and searching strings in arrays

下列範例顯示如何使用相依於目前文化特性的語言比較,在陣列中排序和搜尋字串。The following examples show how to sort and search for strings in an array using a linguistic comparison dependent on the current culture. 請使用接受 System.StringComparer 參數的靜態 Array 方法。You use the static Array methods that take a System.StringComparer parameter.

此範例顯示如何使用目前文化特性來排序字串陣列:This example shows how to sort an array of strings using the current culture:

string[] lines = new string[]
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};

Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Console.WriteLine("\n\rSorted order:");

// Specify Ordinal to demonstrate the different behavior.
Array.Sort(lines, StringComparer.CurrentCulture);

foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

陣列排序之後,您可以使用二進位搜尋來搜尋項目。Once the array is sorted, you can search for entries using a binary search. 二進位搜尋會從集合的中間開始,判斷集合的哪一半會包含搜尋的字串。A binary search starts in the middle of the collection to determine which half of the collection would contain the sought string. 每次後續的比較都會將集合的剩餘部分再對分。Each subsequent comparison subdivides the remaining part of the collection in half. 陣列是使用 StringComparer.CurrentCulture 排序。The array is sorted using the StringComparer.CurrentCulture. 區域函式 ShowWhere 會顯示找到字串處的相關資訊。The local function ShowWhere displays information about where the string was found. 如果找不到字串,則傳回的值會指出如果找到的話它會是在哪裡。If the string was not found, the returned value indicates where it would be if it were found.

string[] lines = new string[]
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};
Array.Sort(lines, StringComparer.CurrentCulture);

string searchString = @"c:\public\TEXTFILE.TXT";
Console.WriteLine($"Binary search for <{searchString}>");
int result = Array.BinarySearch(lines, searchString, StringComparer.CurrentCulture);
ShowWhere<string>(lines, result);

Console.WriteLine($"{(result > 0 ? "Found" : "Did not find")} {searchString}");

void ShowWhere<T>(T[] array, int index)
{
    if (index < 0)
    {
        index = ~index;

        Console.Write("Not found. Sorts between: ");

        if (index == 0)
            Console.Write("beginning of sequence and ");
        else
            Console.Write($"{array[index - 1]} and ");

        if (index == array.Length)
            Console.WriteLine("end of sequence.");
        else
            Console.WriteLine($"{array[index]}.");
    }
    else
    {
        Console.WriteLine($"Found at index {index}.");
    }
}

集合中的序數排序和搜尋Ordinal sorting and searching in collections

下列程式碼會使用 System.Collections.Generic.List<T> 集合類別來儲存字串。The following code uses the System.Collections.Generic.List<T> collection class to store strings. 字串是使用 List<T>.Sort 方法排序。The strings are sorted using the List<T>.Sort method. 這個方法需要可比較和排序兩個字串的委派。This method needs a delegate that compares and orders two strings. String.CompareTo 方法提供該比較函式。The String.CompareTo method provides that comparison function. 執行範例,並觀察順序。Run the sample and observe the order. 此排序作業會使用序數區分大小寫排序。This sort operation uses an ordinal case sensitive sort. 您可以使用靜態 String.Compare 方法來指定不同的比較規則。You would use the static String.Compare methods to specify different comparison rules.

List<string> lines = new List<string>
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};

Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Console.WriteLine("\n\rSorted order:");

lines.Sort((left, right) => left.CompareTo(right)); 
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

排序之後,便可以使用二進位搜尋來搜尋字串清單。Once sorted, the list of strings can be searched using a binary search. 下列範例會示範如何使用相同的比較函式搜尋已排序的清單。The following sample shows how to search the sorted listed using the same comparison function. 區域函式 ShowWhere 顯示搜尋的文字在哪裡或是會在哪裡:The local function ShowWhere shows where the sought text is or would be:

List<string> lines = new List<string>
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};
lines.Sort((left, right) => left.CompareTo(right));

string searchString = @"c:\public\TEXTFILE.TXT";
Console.WriteLine($"Binary search for <{searchString}>");
int result = lines.BinarySearch(searchString);
ShowWhere<string>(lines, result);

Console.WriteLine($"{(result > 0 ? "Found" : "Did not find")} {searchString}");

void ShowWhere<T>(IList<T> collection, int index)
{
    if (index < 0)
    {
        index = ~index;

        Console.Write("Not found. Sorts between: ");

        if (index == 0)
            Console.Write("beginning of sequence and ");
        else
            Console.Write($"{collection[index - 1]} and ");

        if (index == collection.Count)
            Console.WriteLine("end of sequence.");
        else
            Console.WriteLine($"{collection[index]}.");
    }
    else
    {
        Console.WriteLine($"Found at index {index}.");
    }
}

請務必使用相同型別的比較來排序和搜尋。Always make sure to use the same type of comparison for sorting and searching. 使用不同的比較型別來排序和搜尋,會產生非預期的結果。Using different comparison types for sorting and searching produces unexpected results.

項目或索引鍵的類型為 string 時,System.Collections.HashtableSystem.Collections.Generic.Dictionary<TKey,TValue>System.Collections.Generic.List<T> 這類集合類別具有接受 System.StringComparer 參數的建構函式。Collection classes such as System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue>, and System.Collections.Generic.List<T> have constructors that take a System.StringComparer parameter when the type of the elements or keys is string. 通常應該盡可能使用這些建構函式,並指定 StringComparer.OrdinalStringComparer.OrdinalIgnoreCaseIn general, you should use these constructors whenever possible, and specify either StringComparer.Ordinal or StringComparer.OrdinalIgnoreCase.

參考相等與字串暫留Reference equality and string interning

沒有任何範例使用 ReferenceEqualsNone of the samples have used ReferenceEquals. 這個方法會判斷兩個字串是否相同的物件。This method determines if two strings are the same object. 這可能會導致不一致的字串比較結果。This can lead to inconsistent results in string comparisons. 下列範例示範 C# 的「字串暫留」功能。The following example demonstrates the string interning feature of C#. 當程式宣告兩個或多個相同的字串變數時,編譯器會將它們全部儲存在相同的位置。When a program declares two or more identical string variables, the compiler stores them all in the same location. 藉由呼叫 ReferenceEquals 方法,您會看到兩個字串實際上參考記憶體中的相同物件。By calling the ReferenceEquals method, you can see that the two strings actually refer to the same object in memory. 請使用 String.Copy 方法以避免暫留。Use the String.Copy method to avoid interning. 複製完成後,兩個字串會有不同的儲存位置,即使它們有相同的值。After the copy has been made, the two strings have different storage locations, even though they have the same value. 執行下列範例以顯示字串 ab 已「暫留」,也就是說它們共用相同的存放裝置。Run the following sample to show that strings a and b are interned meaning they share the same storage. 字串 ac 則否。The strings a and c are not.

string a = "The computer ate my source code.";
string b = "The computer ate my source code.";

if (String.ReferenceEquals(a, b))
    Console.WriteLine("a and b are interned.");
else
    Console.WriteLine("a and b are not interned.");

string c = String.Copy(a);

if (String.ReferenceEquals(a, c))
    Console.WriteLine("a and c are interned.");
else
    Console.WriteLine("a and c are not interned.");

注意

當您測試字串是否相等時,您應該使用明確指定打算執行比較型別的方法。When you test for equality of strings, you should use the methods that explicitly specify what kind of comparison you intend to perform. 您的程式碼會更容易維護及閱讀。Your code is much more maintainable and readable. 請使用 System.StringSystem.Array 類別的方法多載,接受 StringComparison 列舉參數。Use the overloads of the methods of the System.String and System.Array classes that take a StringComparison enumeration parameter. 您指定要執行的比較型別。You specify which type of comparison to perform. 測試是否相等時,請避免使用 ==!= 運算子。Avoid using the == and != operators when you test for equality. String.CompareTo 執行個體方法一律會執行區分大小寫的序數比較。The String.CompareTo instance methods always perform an ordinal case-sensitive comparison. 它們主要適用於依字母順序排序字串。They are primarily suited for ordering strings alphabetically.

您可以透過呼叫 String.Intern 方法實習字串或擷取參考到現有的已實習字串。You can intern a string or retrieve a reference to an existing interned string by calling the String.Intern method. 若要判斷字串是否已實習,請呼叫 String.IsInterned 方法。To determine whether a string is interned, call the String.IsInterned method.

另請參閱See also