HOW TO:比較字串 (C# 程式設計手冊)

更新: 2008 年 7 月

比較字串時,產生的結果會說明某一個字串大於或小於另一個字串,或是兩個字串相等。用來判斷結果的規則需視執行的是「序數比較」(Ordinal Comparison) 還是「區分文化特性比較」(Culture-Sensitive Comparison) 而定。針對特定工作使用正確的比較類型很重要。

在不考慮語言慣例的情況下,需要比較或排序兩個字串的值時,請使用基本序數比較。基本序數比較 (Ordinal) 必須區分大小寫,也就是說兩個字串的字元必須完全相符:"and" 不等同於 "And" 或 "AND"。最常用的變化是 OrdinalIgnoreCase,亦即 "and"、"And" 和 "AND" 都視為相符。StringComparison.OrdinalIgnoreCase 通常用來比較檔案名稱、路徑名稱、網路路徑,以及其值不會根據使用者電腦的地區設定而改變的任何其他字串。

區分文化特性比較通常用來比較及排序使用者輸入的字串,因為這類字串的字元和排序慣例可能會根據使用者電腦的地區設定而改變。即便字串包含完全相同的字元,也可能會根據目前執行緒的文化特性而有不同的排序方式。

注意事項:

比較字串時,應該使用明確指定要執行何種比較的方法,這樣就能讓程式碼更容易維護及供人們閱讀。請盡可能使用 System.StringSystem.Array 類別 (可使用 StringComparison 列舉型別 (Enumeration) 參數) 之方法的多載,方便指定要執行的比較類型。比較字串時,最好避免使用 == 和 != 運算子。同時,也應避免使用 String.CompareTo 執行個體 (Instance) 方法,因為沒有一個多載會使用 StringComparison

範例

在下列範例中,會針對其值不會根據使用者電腦的地區設定而改變的字串,示範如何正確比較這些字串。此外,還會示範 C# 的「字串暫留」(String Interning) 功能。當程式宣告兩個以上完全相同的字串變數時,編譯器會將它們儲存至相同位置。只要呼叫 ReferenceEquals 方法,就能知道兩個字串實際上是參考到記憶體中的同一個物件。String.Copy 方法可以用來避免暫留功能,如範例中所示。

// Internal strings that will never be localized.
string root = @"C:\users";
string root2 = @"C:\Users";

// Use the overload of the Equals method that specifies a StringComparison.
// Ordinal is the fastest way to compare two strings.
bool result = root.Equals(root2, StringComparison.Ordinal);

Console.WriteLine("Ordinal comparison: {0} and {1} are {2}", root, root2,
                    result ? "equal." : "not equal.");

// To ignore case means "user" equals "User". This is the same as using
// String.ToUpperInvariant on each string and then performing an ordinal comparison.
result = root.Equals(root2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine("Ordinal ignore case: {0} and {1} are {2}", root, root2,
                     result ? "equal." : "not equal.");

// A static method is also available.
bool areEqual = String.Equals(root, root2, StringComparison.Ordinal);


// String interning. Are these really two distinct objects?
string a = "The computer ate my source code.";
string b = "The computer ate my source code.";

// ReferenceEquals returns true if both objects
// point to the same location in memory.
if (String.ReferenceEquals(a, b))
    Console.WriteLine("a and b are interned.");
else
    Console.WriteLine("a and b are not interned.");

// Use String.Copy method to avoid interning.
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.");

在下列範例中,會示範如何透過可使用 StringComparison 列舉型別的 System.String 方法,以慣用方式來比較字串。請注意,這裡不採用 String.CompareTo 執行個體方法,因為沒有一個多載會使用 StringComparison

// "They dance in the street."
// Linguistically (in Windows), "ss" is equal to 
// the German essetz: 'ß' character in both en-US and de-DE cultures.
string first = "Sie tanzen in die Straße."; 
string second = "Sie tanzen in die Strasse.";

Console.WriteLine("First sentence is {0}", first);
Console.WriteLine("Second sentence is {0}", second);

// Store CultureInfo for the current culture. Note that the original culture
// can be set and retrieved on the current thread object.
System.Threading.Thread thread = System.Threading.Thread.CurrentThread;
System.Globalization.CultureInfo originalCulture = thread.CurrentCulture;

// Set the culture to en-US.
thread.CurrentCulture = 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, StringComparison.CurrentCulture);
Console.WriteLine("Comparing in {0} returns {1}.", originalCulture.Name, i);

// Change the current culture to Deutch-Deutchland.
thread.CurrentCulture = new System.Globalization.CultureInfo("de-DE");
i = String.Compare(first, second, StringComparison.CurrentCulture);
Console.WriteLine("Comparing in {0} returns {1}.", thread.CurrentCulture.Name, i);

// For culture-sensitive string equality, use either StringCompare as above
// or the String.Equals overload that takes a StringComparison value.
thread.CurrentCulture = originalCulture;
bool b = String.Equals(first, second, StringComparison.CurrentCulture);
Console.WriteLine("The two strings {0} equal.", b == true ? "are" : "are not");

/*
 * Output:
    First sentence is Sie tanzen in die Straße.
    Second sentence is Sie tanzen in die Strasse.
    Comparing in current culture returns 0.
    The two strings are equal.
 */

在下列範例中,會示範如何透過可使用 System.StringComparer 參數的靜態 Array 方法,以區分文化特性方式來排序及搜尋陣列中的字串。

class SortStringArrays
{
    static void Main()
    {

        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("   {0}", s);
        }

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

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

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


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

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

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

    // Displays where the string was found, or, if not found,
    // where it would have been located.
    private static void ShowWhere<T>(T[] array, int index)
    {
        if (index < 0)
        {
            // If the index is negative, it represents the bitwise
            // complement of the next larger element in the array.
            index = ~index;

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

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

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


}
/*
 * Output:
    Non-sorted order:
       c:\public\textfile.txt
       c:\public\textFile.TXT
       c:\public\Text.txt
       c:\public\testfile2.txt

    Sorted order:
       c:\public\Text.txt
       c:\public\testfile2.txt
       c:\public\textFile.TXT
       c:\public\textfile.txt
    Binary search for c:\public\TEXTFILE.TXT
    Found at index 2.
 */

當元素或索引鍵的型別為 string 時,集合類別 (例如 System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey, TValue>System.Collections.Generic.List<T>) 都有可使用 System.StringComparer 參數的建構函式 (Constructor)。一般而言,您應該盡量使用這些建構函式,並指定 Ordinal 或 OrdinalIgnoreCase。

請參閱

概念

比較字串

參考

字串 (C# 程式設計手冊)

System.Globalization.CultureInfo

System.StringComparer

其他資源

全球化和當地語系化應用程式

變更記錄

日期

記錄

原因

2008 年 7 月

加入主題。

內容 Bug 修正。