Поделиться через


Практическое руководство. Сравнение строк (Руководство по программированию в C#)

В результате сравнения строк оказывается, что одна строка больше или меньше другой, или что обе строки одинаковы. Правила, используемые для определения результата, отличаются в зависимости от выполнения порядкового сравнения или сравнения с учетом языка и региональных параметров. Для каждой отдельной задачи важно использовать соответствующий вид сравнения.

Используйте базовые порядковые сравнения при необходимости сравнить или отсортировать значения двух строк независимо от лингвистических соглашений. В базовом порядковом сравнении (System.StringComparison.Ordinal) учитывается регистр, что означает необходимость соответствия символов двух строк: "and" — не то же, что "And" или "AND". Часто используется вариация System.StringComparison.OrdinalIgnoreCase, которая соответствует написаниям and, And и AND. StringComparison.OrdinalIgnoreCase часто используется для сравнения имен файлов, имен путей, сетевых путей и любой другой строки, значение которой не меняется в зависимости от языка системы компьютера пользователя. Дополнительные сведения см. в разделе StringComparison.

Сравнения с учетом языка и региональных параметров обычно используются для сравнения и сортировки строк, введенных конечными пользователями, поскольку символы и правила сортировки этих строк могут отличаться в зависимости от языкового стандарта компьютера пользователя. Даже строки, содержащие идентичные символы, могут быть отсортированы по-разному, в зависимости от языка и региональных параметров текущего потока.

Примечание

При сравнении строк следует использовать методы, которые явно указывают, какой вид сравнения следует выполнить.Это делает код намного более поддерживаемым и удобочитаемым.По возможности используйте перегрузки методов классов String и Array, которые принимают параметр перечисления StringComparison, чтобы можно было задать тип выполнения сравнения.По возможности рекомендуется избегать использования операторов == и != при сравнении строк.Также рекомендуется избегать использования методов экземпляра String.CompareTo, поскольку ни одна из перегрузок не принимает StringComparison.

Пример

В следующем примере показано, как правильно сравнивать строки, значения которых не изменятся на основе языкового стандарта компьютера пользователя. Кроме того, здесь показано свойство C# изоляция строк. При объявлении программой двух или более идентичных переменных строк компилятор сохраняет их в одном расположении. Вызвав метод 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.");

// Output: 
// Ordinal comparison: C:\users and C:\Users are not equal. 
// Ordinal ignore case: C:\users and C:\Users are equal. 
// a and b are interned. 
// a and c are not interned.

В следующем примере показано, как предпочтительно сравнивать строки с помощью методов String, принимающих перечисление StringComparison. Обратите внимание, что методы экземпляра 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 en-US returns 0.
    Comparing in de-DE returns 0.
    The two strings are equal.
 */

В следующем примере показано, как сортировать и производить поиск строк в массиве с учетом языка и региональных параметров с помощью статических методов Array, принимающих параметр StringComparer.

    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.
     */

Классы коллекций, например Hashtable, Dictionary и List, имеют конструкторы, принимающие параметр StringComparer, когда типом элементов или ключей является string. В целом, по возможности следует использовать эти конструкторы и задавать либо Ordinal, либо OrdinalIgnoreCase.

См. также

Ссылки

CultureInfo

StringComparer

Основные понятия

Сравнение строк в .NET Framework

Другие ресурсы

Строки (Руководство по программированию на C#)

Глобализация и локализация приложений