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

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

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

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

ПримечаниеПримечание

При сравнении строк следует использовать методы, которые явно указывают, какой вид сравнения следует выполнить.Это делает код намного более поддерживаемым и удобочитаемым.По возможности используйте перегрузки методов классов System.String и System.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.

В следующем примере показано, как предпочтительно сравнивать строки с помощью методов System.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 current culture returns 0.
    The two strings are equal.
 */

В следующем примере показано, как сортировать и производить поиск строк в массиве с учетом языка и региональных параметров с помощью статических методов Array, принимающих параметр System.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.
     */

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

См. также

Ссылки

System.Globalization.CultureInfo

System.StringComparer

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

Сравнение строк

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

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

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