Aracılığıyla paylaş


C'de dizeleri karşılaştırma#

Dizeleri iki sorudan birini yanıtlamak için karşılaştırırsınız: "Bu iki dize eşit mi?" veya "Bu dizeler sıralanırken hangi sırada yerleştirilmelidir?"

Aşağıdaki faktörler bu iki soruyu karmaşıklaştırır:

  • Sıralı veya dilsel karşılaştırma seçebilirsiniz.
  • Servis talebinin önemli olup olmadığını seçebilirsiniz.
  • Kültüre özgü karşılaştırmalar seçebilirsiniz.
  • Dil karşılaştırmaları kültüre ve platforma bağımlıdır.

Numaralandırma System.StringComparison alanları şu seçenekleri gösterir:

  • CurrentCulture: Kültüre duyarlı sıralama kurallarını ve geçerli kültürü kullanarak dizeleri karşılaştırın.
  • CurrentCultureIgnoreCase: Kültüre duyarlı sıralama kurallarını, geçerli kültürü kullanarak ve karşılaştırılan dizelerin büyük/küçük harf durumunu yoksayarak dizeleri karşılaştırın.
  • InvariantCulture: Kültüre duyarlı sıralama kurallarını ve sabit kültürü kullanarak dizeleri karşılaştırın.
  • InvariantCultureIgnoreCase: Kültüre duyarlı sıralama kurallarını, değişmez kültürü kullanarak ve karşılaştırılan dizelerin büyük/küçük harflerini göz ardı ederek dizeleri karşılaştırın.
  • Sıralı: Sıralı (ikili) sıralama kurallarını kullanarak dizeleri karşılaştırın.
  • OrdinalIgnoreCase: Sıralı (ikili) sıralama kurallarını kullanarak dizeleri karşılaştırın ve karşılaştırılan dizelerin durumunu yoksayın.

Dizeleri karşılaştırdığınızda, aralarında bir sıra tanımlarsınız. Karşılaştırmalar, bir dizi dizeyi sıralamak için kullanılır. Sıra bilinen bir sırada olduğunda, hem yazılım hem de insanlar için arama yapmak daha kolaydır. Diğer karşılaştırmalar dizelerin aynı olup olmadığını denetleyebilir. Bu benzerlik kontrolleri eşitliğe benzer, ancak büyük/küçük harf farklılıkları gibi bazı farklılıklar yoksayılabilir.

Varsayılan sıralı karşılaştırmalar

Varsayılan olarak, en yaygın işlemler:

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

Varsayılan sıralı karşılaştırma, dizeleri karşılaştırırken dil kurallarını dikkate almaz. İki dizedeki her Char nesnenin ikili değerini karşılaştırır. Sonuç olarak, varsayılan sıralı karşılaştırma da büyük/küçük harfe duyarlıdır.

String.Equals ile eşitlik testi ve == ve != işleçleri, String.CompareTo ve Compare(String, String) yöntemlerini kullanarak yapılan dize karşılaştırmasından farklıdır. Tümü büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. Ancak, eşitlik testleri sıralı bir karşılaştırma gerçekleştirirken ve CompareToCompare yöntemleri geçerli kültürü kullanarak kültüre duyarlı bir dil karşılaştırması gerçekleştirir. Gerçekleştirilecek karşılaştırma türünü açıkça belirten bir aşırı yükleme çağırarak kodunuzun amacını net hale getirin.

Saç işlenen sabitse, =='ye alternatif olarak is işleci ve sabit deseni kullanabilirsiniz.

Büyük/küçük harfe duyarlı olmayan sıralı karşılaştırmalar

Bu String.Equals(String, StringComparison) yöntemi, büyük/küçük harfe duyarsız sıralı karşılaştırma için bir StringComparison değeri belirtmenize StringComparison.OrdinalIgnoreCase olanak tanır. String.Compare(String, String, StringComparison) bağımsız değişkeni için StringComparison.OrdinalIgnoreCase değerini belirlerseniz, büyük/küçük harfe duyarsız sıralı karşılaştırma gerçekleştiren bir statik StringComparison yöntemi de vardır. Bu karşılaştırmalar aşağıdaki kodda gösterilmiştir:

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

Bu yöntemler, büyük/küçük harfe duyarsız sıralı karşılaştırma gerçekleştirirken sabit kültürün büyük/küçük harf kurallarını kullanır.

Dil karşılaştırmaları

Birçok dize karşılaştırma yöntemi (örneğin String.StartsWith), girişlerini sıralamak için varsayılan olarak geçerli kültür için dil kuralları kullanır. Bu dil karşılaştırması bazen "sözcük sıralama düzeni" olarak adlandırılır. Dil karşılaştırması yaptığınızda, bazı nonalfanumerik Unicode karakterlerine özel ağırlıklar atanmış olabilir. Örneğin, tire "-" küçük bir ağırlık verilmiş olabilir, bu sayede "co-op" ve "coop" sıralama düzeninde yan yana görünür. Bazı yazdırılmayan denetim karakterleri göz ardı edilebilir. Ayrıca, bazı Unicode karakterleri bir örnek dizisiyle Char eşdeğer olabilir. Aşağıdaki örnek, "sokakta dans ediyorlar" ifadesini Almanca'da iki farklı şekilde gösterir: birinde "ss" (U+0073 U+0073), diğerinde 'ß' (U+00DF) kullanılarak. Dilbilimsel olarak (Windows'ta), "ss" hem "en-US" hem de "de-DE" kültürlerindeki Almanca Esszet: 'ß' karakterine eşittir.

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

Windows'ta, .NET 5'ten önce, dil karşılaştırmasından sıralı karşılaştırmaya geçiş yaptığınızda "cop", "coop" ve "co-op" sıralama düzeni değişir. İki Almanca cümle de farklı karşılaştırma türleri kullanılarak farklı karşılaştırılır. .NET 5'in öncesinde .NET genelleştirme API'leri Ulusal Dil Desteği (NLS) kitaplıklarını kullanıyordu. .NET 5 ve sonraki sürümlerinde, .NET genelleştirme API'leri, tüm desteklenen işletim sistemlerinde NET'in genelleştirme davranışını birleştiren Uluslararası Bileşenler Unicode (ICU) kitaplıkları kullanır.

Belirli kültürleri kullanan karşılaştırmalar

Aşağıdaki örnek, en-US ve de-DE kültürleri için nesneleri depolar CultureInfo . Karşılaştırmalar, kültüre özgü bir karşılaştırma sağlamak için bir CultureInfo nesne kullanılarak gerçekleştirilir. Kullanılan kültür dil karşılaştırmalarını etkiler. Aşağıdaki örnek, "en-US" kültürü ve "de-DE" kültürü kullanılarak iki Almanca cümlenin karşılaştırılması sonuçlarını gösterir:

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

Kültüre duyarlı karşılaştırmalar, genellikle kullanıcılar tarafından girilen dizeleri diğer kullanıcılar tarafından girilen dizelerle karşılaştırmak ve sıralamak için kullanılır. Bu dizelerin karakterleri ve sıralama kuralları, kullanıcının bilgisayarının yerel ayarına bağlı olarak değişebilir. Aynı karakterleri içeren dizeler bile geçerli iş parçacığının kültürüne bağlı olarak farklı sıralanabilir.

Dizilerdeki dizeleri dilsel sıralama ve arama

Aşağıdaki örneklerde, geçerli kültüre bağımlı bir dil karşılaştırması kullanarak dizideki dizeleri sıralama ve arama işlemleri gösterilmektedir. Statik Array yöntemlerini, bir System.StringComparer parametresi alan, kullanırsınız.

Aşağıdaki örnek, geçerli kültürü kullanarak bir dize dizisinin nasıl sıralanacağını gösterir:

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

Dizi sıralandıktan sonra, ikili arama kullanarak girdileri arayabilirsiniz. İkili arama, koleksiyonun hangi yarısının aranan dizeyi içereceğini belirlemek için koleksiyonun ortasında başlar. Sonraki her karşılaştırma, koleksiyonun kalan bölümünü yarıya böler. Dizi, StringComparer.CurrentCulture kullanılarak sıralanır. Yerel işlev ShowWhere , dizenin bulunduğu yerle ilgili bilgileri görüntüler. Dize bulunamazsa, döndürülen değer bulunursa nerede olacağını gösterir.

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

Koleksiyonlarda sıralı sıralama ve arama

Aşağıdaki kod, dizeleri depolamak için koleksiyon sınıfını kullanır System.Collections.Generic.List<T> . Dizeler yöntemi kullanılarak List<T>.Sort sıralanır. Bu yöntem, iki dizeyi karşılaştıran ve sıralayan bir temsilciye ihtiyaç duyar. yöntemi bu String.CompareTo karşılaştırma işlevini sağlar. Örneği çalıştırın ve sırayı gözlemleyin. Bu sıralama işlemi düzenli ve büyük/küçük harfe duyarlı bir sıralama kullanır. Farklı karşılaştırma kuralları belirtmek için statik String.Compare yöntemleri kullanırsınız.

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

Sıralandıktan sonra, dize listesi ikili arama kullanılarak aranabilir. Aşağıdaki örnek, aynı karşılaştırma işlevini kullanarak sıralanmış listede nasıl arama yapılacağını gösterir. Yerel işlev ShowWhere aranan metnin nerede olduğunu veya olacağını gösterir:

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

Sıralama ve arama için her zaman aynı karşılaştırma türünü kullandığınızdan emin olun. Sıralama ve arama için farklı karşılaştırma türlerinin kullanılması beklenmeyen sonuçlara neden olur.

System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue> ve System.Collections.Generic.List<T> gibi koleksiyon sınıflarının, öğelerin veya anahtarların türü string olduğunda bir System.StringComparer parametresi alan oluşturucuları vardır. Genel olarak, mümkün olduğunda bu oluşturucuları kullanmalı ve StringComparer.Ordinal veya StringComparer.OrdinalIgnoreCase belirtmelisiniz.

Ayrıca bakınız