Delen via


Tekenreeksen vergelijken in C#

U vergelijkt tekenreeksen om een van de twee vragen te beantwoorden: 'Zijn deze twee tekenreeksen gelijk?' of 'In welke volgorde moeten deze tekenreeksen worden geplaatst wanneer ze worden gesorteerd?'

Deze twee vragen zijn ingewikkeld door factoren die van invloed zijn op tekenreeksvergelijkingen:

  • U kunt een ordinale of taalkundige vergelijking kiezen.
  • U kunt kiezen of het geval van belang is.
  • U kunt cultuurspecifieke vergelijkingen kiezen.
  • Taalkundige vergelijkingen zijn cultuur en platformafhankelijk.

De System.StringComparison opsommingsvelden vertegenwoordigen deze opties:

  • CurrentCulture: Vergelijk tekenreeksen met behulp van cultuurgevoelige sorteerregels en de huidige cultuur.
  • CurrentCultureIgnoreCase: Vergelijk tekenreeksen met behulp van cultuurgevoelige sorteerregels, de huidige cultuur en negeer het geval van de tekenreeksen die worden vergeleken.
  • InvariantCulture: Vergelijk tekenreeksen met behulp van cultuurgevoelige sorteerregels en de invariante cultuur.
  • InvariantCultureIgnoreCase: Vergelijk tekenreeksen met cultuurgevoelige sorteerregels, de invariante cultuur en negeer het geval van de tekenreeksen die worden vergeleken.
  • Rangschikken: tekenreeksen vergelijken met behulp van ordinale (binaire) sorteerregels.
  • OrdinalIgnoreCase: Vergelijk tekenreeksen met behulp van ordinale (binaire) sorteerregels en negeer het geval van de tekenreeksen die worden vergeleken.

Notitie

De C#-voorbeelden in dit artikel worden uitgevoerd in de Try.NET inline coderunner en playground. Selecteer de knop Uitvoeren om een voorbeeld uit te voeren in een interactief venster. Nadat u de code hebt uitgevoerd, kunt u deze wijzigen en de gewijzigde code uitvoeren door Opnieuw uitvoeren te selecteren. De gewijzigde code wordt uitgevoerd in het interactieve venster of, als de compilatie mislukt, worden alle C#-compilerfoutberichten weergegeven.

Wanneer u tekenreeksen vergelijkt, definieert u een volgorde tussen deze tekenreeksen. Vergelijkingen worden gebruikt om een reeks tekenreeksen te sorteren. Zodra de volgorde zich in een bekende volgorde bevindt, is het gemakkelijker om te zoeken, zowel voor software als voor mensen. Andere vergelijkingen kunnen controleren of tekenreeksen hetzelfde zijn. Deze zelfdeheidscontroles zijn vergelijkbaar met gelijkheid, maar sommige verschillen, zoals caseverschillen, kunnen worden genegeerd.

Standaard ordinale vergelijkingen

De meest voorkomende bewerkingen zijn standaard:

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

Bij het vergelijken van tekenreeksen wordt bij het vergelijken van tekenreeksen geen rekening gehouden met de standaard ordinale vergelijking. Hiermee wordt de binaire waarde van elk Char object in twee tekenreeksen vergeleken. Als gevolg hiervan is de standaard ordinale vergelijking ook hoofdlettergevoelig.

De test voor gelijkheid met String.Equals en de == operatoren != verschilt van tekenreeksvergelijking met behulp van de String.CompareTo en Compare(String, String) methoden. Ze voeren allemaal een hoofdlettergevoelige vergelijking uit. Hoewel de tests op gelijkheid echter een rangtelvergelijking uitvoeren, voeren de CompareTo en Compare methoden een cultuurbewuste taalkundige vergelijking uit met behulp van de huidige cultuur. Maak de intentie van uw code duidelijk door een overbelasting aan te roepen die expliciet het type vergelijking aangeeft dat moet worden uitgevoerd.

Hoofdlettergevoelige ordinale vergelijkingen

Met de String.Equals(String, StringComparison) methode kunt u een StringComparison waarde opgeven voor StringComparison.OrdinalIgnoreCase een niet-hoofdlettergevoelige ordinale vergelijking. Er is ook een statische String.Compare(String, String, StringComparison) methode waarmee een niet-hoofdlettergevoelige ordinale vergelijking wordt uitgevoerd als u een waarde StringComparison.OrdinalIgnoreCase voor het StringComparison argument opgeeft. Deze vergelijkingen worden weergegeven in de volgende code:

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

Deze methoden gebruiken de casingconventies van de invariante cultuur bij het uitvoeren van een hoofdlettergevoelige ordinale vergelijking.

Taalkundige vergelijkingen

Veel tekenreeksvergelijkingsmethoden (zoals String.StartsWith) gebruiken standaard taalkundige regels voor de huidige cultuur om hun invoer te orden. Deze taalkundige vergelijking wordt soms aangeduid als 'sorteervolgorde voor woorden'. Wanneer u een taalkundige vergelijking uitvoert, zijn er mogelijk speciale gewichten toegewezen aan bepaalde niet-phanumerische Unicode-tekens. Het afbreekstreepje '-' kan bijvoorbeeld een klein gewicht hebben, zodat 'co-op' en 'coop' naast elkaar worden weergegeven in sorteervolgorde. Sommige niet-afdrukbare besturingstekens worden mogelijk genegeerd. Daarnaast zijn sommige Unicode-tekens mogelijk gelijk aan een reeks Char exemplaren. In het volgende voorbeeld wordt de zin 'Ze dansen in de straat'. In het Duits met de 'ss' (U+0073 U+0073) in één tekenreeks en 'ß' (U+00DF) in een andere. Taalkundig (in Windows) is "ss" gelijk aan het Duitse Esszet: 'ß' karakter in zowel de culturen "en-US" als "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");
}

In Windows, vóór .NET 5, verandert de sorteervolgorde van 'cop', 'coop' en 'co-op' wanneer u overstapt van een taalkundige vergelijking naar een ordinale vergelijking. De twee Duitse zinnen vergelijken ook verschillend met behulp van de verschillende vergelijkingstypen. Vóór .NET 5 gebruikten de .NET globalization-API's nationale taalondersteuning (NLS) -bibliotheken. In .NET 5 en latere versies maken de .NET Globalization-API's gebruik van ICU-bibliotheken (International Components for Unicode). Het globalisatiegedrag van NET voor alle ondersteunde besturingssystemen.

Vergelijkingen met behulp van specifieke culturen

In het volgende voorbeeld worden objecten opgeslagen CultureInfo voor de en-US- en de-DE-culturen. De vergelijkingen worden uitgevoerd met behulp van een CultureInfo object om een cultuurspecifieke vergelijking te garanderen. De gebruikte cultuur is van invloed op taalkundige vergelijkingen. In het volgende voorbeeld ziet u de resultaten van het vergelijken van de twee Duitse zinnen met behulp van de "en-US"-cultuur en de "de-DE"-cultuur:

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

Cultuurgevoelige vergelijkingen worden meestal gebruikt voor het vergelijken en sorteren van tekenreeksinvoer door gebruikers met andere tekenreeksinvoer door gebruikers. De tekens en sorteerconventies van deze tekenreeksen kunnen variëren, afhankelijk van de landinstelling van de computer van de gebruiker. Zelfs tekenreeksen die identieke tekens bevatten, kunnen anders sorteren, afhankelijk van de cultuur van de huidige thread.

Taalkundige sorteer- en zoektekenreeksen in matrices

In de volgende voorbeelden ziet u hoe u tekenreeksen in een matrix sorteert en zoekt met behulp van een taalkundige vergelijking die afhankelijk is van de huidige cultuur. U gebruikt de statische Array methoden die een System.StringComparer parameter gebruiken.

In het volgende voorbeeld ziet u hoe u een matrix met tekenreeksen sorteert met behulp van de huidige cultuur:

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

Zodra de matrix is gesorteerd, kunt u zoeken naar items met behulp van een binaire zoekopdracht. Een binaire zoekopdracht begint in het midden van de verzameling om te bepalen welke helft van de verzameling de gezochte tekenreeks zou bevatten. Bij elke volgende vergelijking wordt het resterende deel van de verzameling in de helft onderverdeeld. De matrix wordt gesorteerd met behulp van de StringComparer.CurrentCulture. De lokale functie ShowWhere geeft informatie weer over waar de tekenreeks is gevonden. Als de tekenreeks niet is gevonden, geeft de geretourneerde waarde aan waar deze zou zijn als deze werd gevonden.

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

Rangschikk sorteren en zoeken in verzamelingen

De volgende code maakt gebruik van de verzamelingsklasse voor het System.Collections.Generic.List<T> opslaan van tekenreeksen. De tekenreeksen worden gesorteerd met behulp van de List<T>.Sort methode. Deze methode heeft een gemachtigde nodig die twee tekenreeksen vergelijkt en bestelt. De String.CompareTo methode biedt die vergelijkingsfunctie. Voer het voorbeeld uit en bekijk de volgorde. Deze sorteerbewerking maakt gebruik van een ordinale hoofdlettergevoelige sortering. U gebruikt de statische String.Compare methoden om verschillende vergelijkingsregels op te geven.

List<string> lines = new List<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($"   {s}");
}

Console.WriteLine("\n\rSorted order:");

lines.Sort((left, right) => left.CompareTo(right));
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Zodra deze is gesorteerd, kan de lijst met tekenreeksen worden doorzocht met behulp van een binaire zoekopdracht. In het volgende voorbeeld ziet u hoe u in de gesorteerde lijst kunt zoeken met dezelfde vergelijkingsfunctie. De lokale functie ShowWhere geeft aan waar de gezochte tekst is of zou zijn:

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

Zorg er altijd voor dat u hetzelfde type vergelijking gebruikt voor sorteren en zoeken. Het gebruik van verschillende vergelijkingstypen voor sorteren en zoeken levert onverwachte resultaten op.

Verzamelingsklassen zoals System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue>en System.Collections.Generic.List<T> hebben constructors die een System.StringComparer parameter gebruiken wanneer het type elementen of sleutels is string. Over het algemeen moet u deze constructors waar mogelijk gebruiken en opgeven of StringComparer.OrdinalStringComparer.OrdinalIgnoreCase.

Zie ook