Porównywanie ciągów w języku C#

Wskazówka

Ten artykuł jest częścią sekcji Podstawy dla deweloperów, którzy już znają co najmniej jeden język programowania i uczą się języka C#. Jeśli dopiero zaczynasz programować, najpierw zacznij od samouczków Wprowadzenie .

Pochodzi z innego języka? C# == dla łańcuchów porównuje wartości, a nie referencje, podobnie jak w Java equals lub JavaScript ===. Kluczowa różnica polega na tym, że język C# umożliwia wybór między porównaniem porządkowym (binarnym) a porównaniem z uwzględnieniem kultury za pomocą wartości StringComparison.

Porównujesz ciągi, aby odpowiedzieć na jedno z dwóch pytań: czy te dwa ciągi są równe? czy w jakiej kolejności te ciągi są sortowane? Język C# umożliwia kontrolowanie dwóch niezależnych czynników podczas odpowiadania na oba pytania:

  • Rozróżnianie wielkości liter — określa, czy "Hello" i "hello" są traktowane jako równe.
  • Rodzaj porównaniaporządkowy (porównaj wartość binarną każdego znaku) lub świadomy kultury (zastosuj reguły językowe kultury).

Wyliczenie StringComparison łączy te czynniki w jedną wartość przekazywaną do metod porównania.

Porównaj pod kątem równości

Metoda String.Equals i operator == domyślnie wykonują porównanie z uwzględnieniem wielkości liter i wartości porządkowej. Porównanie porządkowe sprawdza wartość binarną każdego znaku, więc jest szybkie i daje ten sam wynik na każdej maszynie. Możesz jawnie określić zamiar, wywołując przeciążenie, które przyjmuje wartość StringComparison:

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

// Equals and == both perform a case-sensitive, ordinal comparison.
Console.WriteLine(root.Equals(root2));
// => False
Console.WriteLine(root == root2);
// => False

// Pass a StringComparison value to state the intent explicitly.
Console.WriteLine(root.Equals(root2, StringComparison.Ordinal));
// => False

Aby zignorować przypadek podczas utrzymywania semantyki porządkowej, przekaż polecenie StringComparison.OrdinalIgnoreCase:

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

// OrdinalIgnoreCase compares the binary values but ignores case.
bool equalIgnoringCase = string.Equals(root, root2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine(equalIgnoringCase);
// => True

Porównaj według kolejności sortowania

Aby określić kolejność sortowania, a nie równość, użyj polecenia String.Compare. Zwraca liczbę ujemną, zero lub liczbę dodatnią, aby wskazać, czy pierwszy ciąg sortuje przed, w tej samej pozycji co, czy po drugim:

string first = "Avocado";
string second = "Banana";

// Compare returns a negative number, zero, or a positive number
// to indicate sort order. Specify the comparison type explicitly.
int order = string.Compare(first, second, StringComparison.Ordinal);
Console.WriteLine(order < 0
    ? $"'{first}' sorts before '{second}'."
    : $"'{first}' sorts at or after '{second}'.");
// => 'Avocado' sorts before 'Banana'.

Ważna

Compare i CompareTo domyślnie używają porównania z uwzględnieniem ustawień regionalnych, natomiast Equals i == domyślnie używają porównania porządkowego. Aby uniknąć niespodzianek, przekaż jawną StringComparison wartość, aby kod określał, które zachowanie chce.

Porównywanie ze stałymi za pomocą dopasowywania do wzorca is lub switch

Gdy porównywana wartość jest stałą, możesz użyć is operatora ze stałym wzorcem jako czytelnej alternatywy dla ==elementu :

string status = "Ready";

// When the right operand is a constant, the is operator and a
// constant pattern read as an alternative to ==.
if (status is "Ready")
{
    Console.WriteLine("The system is ready.");
}
// => The system is ready.

Aby porównać ciąg z kilkoma stałymi, użyj switch wyrażenia. Każde ramię testuje stały wzorzec, a wzorzec odrzucenia (_) obsługuje każdą wartość, która nie jest zgodna. Poniższy przykład przyporządkowuje słowo kluczowe określające kierunek do wskazówki dotyczącej podróży:

foreach (string heading in new[] { "North", "South", "East", "West", "NE" })
{
    // A switch expression matches each constant pattern in turn and
    // returns the first match. The discard (_) handles every other value.
    string instruction = heading switch
    {
        "North" => "Travel due North for 10 km.",
        "South" => "Travel due South for 10 km.",
        "East" => "Travel due East for 10 km.",
        "West" => "Travel due West for 10 km.",
        _ => $"Unknown heading: {heading}.",
    };
    Console.WriteLine(instruction);
}
// => Travel due North for 10 km.
// => Travel due South for 10 km.
// => Travel due East for 10 km.
// => Travel due West for 10 km.
// => Unknown heading: NE.

Wyrażenie switch, które sprawdza stałe ciągów znaków, wykonuje to samo porównanie porządkowe z uwzględnieniem wielkości liter co ==, więc "north" nie pasuje do gałęzi "North".

Wybieranie odpowiedniego porównania

Wybierz rodzaj porównania na podstawie danych, a nie z nawyku:

  • W przypadku identyfikatorów, ścieżek plików, tokenów protokołu i innego tekstu zdefiniowanego przez maszynę użyj znacznika Ordinal (lub OrdinalIgnoreCase, aby nie uwzględniać wielkości liter). Porównywanie porządkowe jest szybkie i spójne niezależnie od kultury.
  • W przypadku tekstu, który użytkownicy odczytują i sortują, takiego jak nazwy lub tytuły produktów, użyj CurrentCulture, aby kolejność odpowiadała oczekiwaniom użytkownika.

Porównanie oparte na kulturze stosuje reguły językowe, które różnią się w zależności od kultury i mogą powodować zaskakujące wyniki. Na przykład niektóre kultury traktują "ss" i "ß" jako równe, a kolejność łańcuchów może się zmieniać między maszynami. Ze względu na tę zmienność, należy zarezerwować porównanie z uwzględnieniem kultury dla oryginalnego tekstu w języku naturalnym i używać tego samego rodzaju porównania przy każdym sortowaniu i wyszukiwaniu kolekcji.

Aby zapoznać się ze szczegółowym omówieniem porównywania z uwzględnieniem ustawień kulturowych, w tym zagadnień dotyczących globalizacji i różnic między platformami, zobacz Najlepsze praktyki dotyczące porównywania ciągów w .NET.

Zobacz także