Bagikan melalui


Cara membandingkan string di C#

Anda membandingkan string untuk menjawab salah satu dari dua pertanyaan: "Apakah kedua string ini sama?" atau "Dalam urutan apa string ini harus ditempatkan saat mengurutkannya?"

Faktor-faktor berikut mempersulit kedua pertanyaan ini:

  • Anda dapat memilih perbandingan ordinal atau linguistik.
  • Anda dapat memilih apakah kasus penting.
  • Anda dapat memilih perbandingan khusus budaya.
  • Perbandingan linguistik tergantung pada budaya dan platform.

Bidang System.StringComparison enumerasi mewakili pilihan ini:

  • CurrentCulture: Bandingkan string menggunakan aturan pengurutan sensitif budaya dan budaya saat ini.
  • CurrentCultureIgnoreCase: Bandingkan string menggunakan aturan pengurutan sensitif budaya, budaya saat ini, dan mengabaikan kasus string yang dibandingkan.
  • InvariantCulture: Bandingkan string menggunakan aturan pengurutan sensitif budaya dan budaya invarian.
  • InvariantCultureIgnoreCase: Bandingkan string menggunakan aturan pengurutan sensitif budaya, budaya invarian, dan mengabaikan kasus string yang dibandingkan.
  • Ordinal: Bandingkan string menggunakan aturan pengurutan ordinal (biner).
  • OrdinalIgnoreCase: Bandingkan string menggunakan aturan pengurutan ordinal (biner) dan mengabaikan kasus string yang dibandingkan.

Saat membandingkan string, Anda menentukan urutan di antaranya. Perbandingan digunakan untuk mengurutkan urutan string. Setelah urutannya dalam urutan yang diketahui, lebih mudah untuk mencari, baik untuk perangkat lunak maupun untuk manusia. Perbandingan lain mungkin memeriksa apakah string tersebut sama persis. Pemeriksaan kesamaan ini mirip dengan kesetaraan, tetapi beberapa perbedaan, seperti perbedaan kasus, mungkin diabaikan.

Perbandingan default ordinal

Secara default, operasi yang paling umum:

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")}");

Perbandingan ordinal default tidak memperhitungkan aturan linguistik saat membandingkan string. Ini membandingkan nilai biner dari setiap Char objek dalam dua string. Akibatnya, perbandingan ordinal default juga peka huruf besar/kecil.

Pengujian untuk kesetaraan dengan String.Equals dan operator == serta != berbeda dari perbandingan string menggunakan metode String.CompareTo dan Compare(String, String). Semuanya melakukan perbandingan yang peka terhadap besar kecilnya huruf. Sementara uji kesetaraan melakukan perbandingan ordinal, metode CompareTo dan Compare melakukan perbandingan linguistik yang memperhatikan budaya dengan menggunakan budaya yang sedang digunakan. Buat niat kode Anda jelas dengan memanggil kelebihan beban yang secara eksplisit menentukan jenis perbandingan yang akan dilakukan.

Anda dapat menggunakan is operator dan pola konstanta sebagai alternatif == ketika operand kanan adalah konstanta.

Perbandingan ordinal yang tidak peka huruf besar/kecil

Metode String.Equals(String, StringComparison) memungkinkan Anda menentukan nilai StringComparison dari StringComparison.OrdinalIgnoreCase untuk perbandingan ordinal yang tidak peka huruf besar/kecil. Ada juga metode statis String.Compare(String, String, StringComparison) yang melakukan perbandingan ordinal tanpa membedakan huruf besar/kecil jika Anda menentukan nilai StringComparison.OrdinalIgnoreCase untuk argumen StringComparison. Perbandingan ini ditampilkan dalam kode berikut:

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");
}

Metode ini menggunakan konvensi penulisan huruf dari budaya invarian saat melakukan perbandingan ordinal yang tidak membedakan besar-kecil huruf.

Perbandingan linguistik

Banyak metode perbandingan string (seperti String.StartsWith) menggunakan aturan linguistik untuk kebudayaan saat ini secara default untuk mengurutkan input mereka. Perbandingan linguistik ini terkadang disebut sebagai "urutan pengurutan kata." Ketika Anda melakukan perbandingan linguistik, beberapa karakter Unicode non-phanumeric mungkin memiliki bobot khusus yang ditetapkan. Misalnya, tanda hubung "-" mungkin memiliki bobot kecil yang ditetapkan untuk itu sehingga "co-op" dan "coop" muncul berdampingan dalam urutan pengurutan. Beberapa karakter kontrol noncetak mungkin diabaikan. Selain itu, beberapa karakter Unicode mungkin sama dengan rangkaian Char instance. Contoh berikut menggunakan frasa "Mereka menari di jalan." dalam bahasa Jerman dengan "ss" (U+0073 U+0073) dalam satu string dan 'ß' (U+00DF) di string lain. Secara linguistik (dalam Windows), "ss" sama dengan karakter Esszet Jerman: 'ß' dalam budaya "en-US" dan "de-DE".

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");
    }
}

Pada Windows, sebelum .NET 5, urutan "cop", "coop", dan "co-op" berubah ketika Anda beralih dari perbandingan berdasarkan linguistik ke perbandingan ordinal. Kedua kalimat Jerman juga dibandingkan secara berbeda menggunakan berbagai jenis perbandingan. Sebelum .NET 5, API globalisasi .NET menggunakan pustaka Dukungan Bahasa Nasional (NLS ). Di .NET 5 dan versi yang lebih baru, API globalisasi .NET menggunakan pustaka Komponen Internasional untuk Unicode (ICU) yang menyatukan perilaku globalisasi .NET di semua sistem operasi yang didukung.

Perbandingan menggunakan budaya tertentu

Contoh berikut menyimpan CultureInfo objek untuk budaya en-US dan de-DE. Perbandingan dilakukan menggunakan CultureInfo objek untuk memastikan perbandingan khusus budaya. Budaya yang digunakan mempengaruhi perbandingan linguistik. Contoh berikut menunjukkan hasil membandingkan dua kalimat Jerman menggunakan budaya "en-US" dan budaya "de-DE":

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");
    }
}

Perbandingan sensitif budaya biasanya digunakan untuk membandingkan dan mengurutkan string yang dimasukkan oleh pengguna dengan string lain yang diinput oleh pengguna. Karakter dan konvensi pengurutan string ini mungkin bervariasi tergantung pada lokal komputer pengguna. Bahkan string yang berisi karakter identik mungkin diurutkan dengan cara yang berbeda tergantung pada budaya thread yang sedang digunakan.

Pengurutan linguistik dan mencari string dalam array

Contoh berikut menunjukkan cara mengurutkan dan mencari string dalam array menggunakan perbandingan linguistik tergantung pada budaya saat ini. Anda menggunakan metode statis Array yang mengambil System.StringComparer parameter.

Contoh berikut menunjukkan cara mengurutkan array string menggunakan budaya saat ini:

string[] lines =
[
    @"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}");
}

Setelah array diurutkan, Anda dapat mencari entri menggunakan pencarian biner. Pencarian biner dimulai di tengah koleksi untuk menentukan setengah koleksi mana yang akan berisi string yang dicari. Setiap perbandingan berikutnya membagi bagian yang tersisa dari koleksi menjadi setengah. Array diurutkan menggunakan StringComparer.CurrentCulture. Fungsi ShowWhere lokal menampilkan informasi tentang tempat string ditemukan. Jika string tidak ditemukan, nilai yang dikembalikan menunjukkan lokasinya jika ditemukan.

string[] lines =
[
    @"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}.");
    }
}

Pengurutan dan pencarian ordinal dalam koleksi

Kode berikut menggunakan System.Collections.Generic.List<T> kelas koleksi untuk menyimpan string. String diurutkan menggunakan List<T>.Sort metode . Metode ini membutuhkan delegasi yang membandingkan dan mengurutkan dua string. Metode ini String.CompareTo menyediakan fungsi perbandingan tersebut. Jalankan contoh dan amati urutan. Operasi pengurutan ini menggunakan pengurutan sensitif kasus ordinal. Anda akan menggunakan metode statis String.Compare untuk menentukan aturan perbandingan yang berbeda.

List<string> lines =
[
    @"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}");
}

Setelah diurutkan, daftar string dapat dicari menggunakan pencarian biner. Contoh berikut menunjukkan cara mencari daftar yang diurutkan menggunakan fungsi perbandingan yang sama. Fungsi ShowWhere lokal menunjukkan di mana teks yang dicari adalah atau akan:

List<string> lines =
[
    @"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}.");
    }
}

Selalu pastikan untuk menggunakan jenis perbandingan yang sama untuk pengurutan dan pencarian. Menggunakan jenis perbandingan yang berbeda untuk pengurutan dan pencarian menghasilkan hasil yang tidak terduga.

Kelas koleksi seperti System.Collections.Hashtable, , dan System.Collections.Generic.Dictionary<TKey,TValue> memiliki konstruktor yang mengambil System.Collections.Generic.List<T> parameter ketika jenis elemen atau kunci adalah System.StringComparerstring. Secara umum, Anda harus menggunakan konstruktor ini jika memungkinkan, dan menentukan StringComparer.Ordinal atau StringComparer.OrdinalIgnoreCase.

Lihat juga