System.String-Klasse

Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.

Eine Zeichenfolge ist eine sequenzielle Auflistung von Zeichen, die zum Darstellen von Text verwendet werden. Ein String Objekt ist eine sequenzielle Auflistung von System.Char Objekten, die eine Zeichenfolge darstellen; ein System.Char Objekt entspricht einer UTF-16-Codeeinheit. Der Wert des String Objekts ist der Inhalt der sequenziellen Auflistung von System.Char Objekten, und dieser Wert ist unveränderlich (d. a. schreibgeschützt). Weitere Informationen zur Unveränderlichkeit von Zeichenfolgen finden Sie im Abschnitt "Unveränderlichkeit" und "StringBuilder" . Die maximale Größe eines String Objekts im Arbeitsspeicher beträgt 2 GB oder etwa 1 Milliarden Zeichen.

Weitere Informationen zu Unicode, UTF-16, Codeeinheiten, Codepunkten und den Char Typen Rune finden Sie unter Einführung in die Zeichencodierung in .NET.

Instanziieren eines String-Objekts

Sie können ein String Objekt auf folgende Weise instanziieren:

  • Durch Zuweisen eines Zeichenfolgenliterals zu einer String Variablen. Dies ist die am häufigsten verwendete Methode zum Erstellen einer Zeichenfolge. Im folgenden Beispiel wird eine Zuordnung verwendet, um mehrere Zeichenfolgen zu erstellen. Beachten Sie, dass in C# und F#, da der umgekehrte Schrägstrich (\) ein Escapezeichen ist, literale umgekehrte Schrägstriche in einer Zeichenfolge escaped sein müssen oder die gesamte Zeichenfolge @-zitiert sein muss.

    string string1 = "This is a string created by assignment.";
    Console.WriteLine(string1);
    string string2a = "The path is C:\\PublicDocuments\\Report1.doc";
    Console.WriteLine(string2a);
    string string2b = @"The path is C:\PublicDocuments\Report1.doc";
    Console.WriteLine(string2b);
    // The example displays the following output:
    //       This is a string created by assignment.
    //       The path is C:\PublicDocuments\Report1.doc
    //       The path is C:\PublicDocuments\Report1.doc
    
    let string1 = "This is a string created by assignment."
    printfn "%s" string1
    let string2a = "The path is C:\\PublicDocuments\\Report1.doc"
    printfn "%s" string2a
    let string2b = @"The path is C:\PublicDocuments\Report1.doc"
    printfn "%s" string2b
    // The example displays the following output:
    //       This is a string created by assignment.
    //       The path is C:\PublicDocuments\Report1.doc
    //       The path is C:\PublicDocuments\Report1.doc
    
    Dim string1 As String = "This is a string created by assignment."
    Console.WriteLine(string1)
    Dim string2 As String = "The path is C:\PublicDocuments\Report1.doc"
    Console.WriteLine(string2)
    ' The example displays the following output:
    '       This is a string created by assignment.
    '       The path is C:\PublicDocuments\Report1.doc
    
  • Durch Aufrufen eines String Klassenkonstruktors. Im folgenden Beispiel werden Zeichenfolgen instanziiert, indem mehrere Klassenkonstruktoren aufgerufen werden. Beachten Sie, dass einige der Konstruktoren Zeiger auf Zeichenarrays oder signierte Bytearrays als Parameter enthalten. Visual Basic unterstützt keine Aufrufe dieser Konstruktoren. Ausführliche Informationen zu String Konstruktoren finden Sie in der String Konstruktorzusammenfassung.

    char[] chars = { 'w', 'o', 'r', 'd' };
    sbyte[] bytes = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x00 };
    
    // Create a string from a character array.
    string string1 = new string(chars);
    Console.WriteLine(string1);
    
    // Create a string that consists of a character repeated 20 times.
    string string2 = new string('c', 20);
    Console.WriteLine(string2);
    
    string stringFromBytes = null;
    string stringFromChars = null;
    unsafe
    {
       fixed (sbyte* pbytes = bytes)
       {
          // Create a string from a pointer to a signed byte array.
          stringFromBytes = new string(pbytes);
       }
       fixed (char* pchars = chars)
       {
          // Create a string from a pointer to a character array.
          stringFromChars = new string(pchars);
       }
    }
    Console.WriteLine(stringFromBytes);
    Console.WriteLine(stringFromChars);
    // The example displays the following output:
    //       word
    //       cccccccccccccccccccc
    //       ABCDE
    //       word
    
    let chars = [| 'w'; 'o'; 'r'; 'd' |]
    let bytes = [| 0x41y; 0x42y; 0x43y; 0x44y; 0x45y; 0x00y |]
    
    // Create a string from a character array.
    let string1 = String chars
    printfn "%s" string1
    
    // Create a string that consists of a character repeated 20 times.
    let string2 = String('c', 20)
    printfn "%s" string2
    
    let stringFromBytes =
        // Create a string from a pointer to a signed byte array.
        use pbytes = fixed bytes
        String pbytes
    let stringFromChars = 
        // Create a string from a pointer to a character array.
        use pchars = fixed chars
        String pchars
    
    printfn $"{stringFromBytes}"
    printfn $"{stringFromChars}"
    // The example displays the following output:
    //       word
    //       cccccccccccccccccccc
    //       ABCDE
    //       word
    
    Dim chars() As Char = {"w"c, "o"c, "r"c, "d"c}
    
    ' Create a string from a character array.
    Dim string1 As New String(chars)
    Console.WriteLine(string1)
    
    ' Create a string that consists of a character repeated 20 times.
    Dim string2 As New String("c"c, 20)
    Console.WriteLine(string2)
    ' The example displays the following output:
    '       word
    '       cccccccccccccccccccc
    
  • Mithilfe des Zeichenfolgenverkettungsoperators (+ in C# und F# und & oder + in Visual Basic) können Sie eine einzelne Zeichenfolge aus einer beliebigen Kombination von String Instanzen und Zeichenfolgenliteralen erstellen. Das folgende Beispiel veranschaulicht die Verwendung des Zeichenfolgenverkettungsoperators.

    string string1 = "Today is " + DateTime.Now.ToString("D") + ".";
    Console.WriteLine(string1);
    
    string string2 = "This is one sentence. " + "This is a second. ";
    string2 += "This is a third sentence.";
    Console.WriteLine(string2);
    // The example displays output like the following:
    //    Today is Tuesday, July 06, 2011.
    //    This is one sentence. This is a second. This is a third sentence.
    
    let string1 = "Today is " + DateTime.Now.ToString("D") + "."
    printfn $"{string1}"
    
    let string2 = "This is one sentence. " + "This is a second. "
    let string2 = string2 + "This is a third sentence."
    printfn $"{string2}"
    // The example displays output like the following:
    //    Today is Tuesday, July 06, 2011.
    //    This is one sentence. This is a second. This is a third sentence.
    
    Dim string1 As String = "Today is " + Date.Now.ToString("D") + "."
    Console.WriteLine(string1)
    Dim string2 As String = "This is one sentence. " + "This is a second. "
    string2 += "This is a third sentence."
    Console.WriteLine(string2)
    ' The example displays output like the following:
    '    Today is Tuesday, July 06, 2011.
    '    This is one sentence. This is a second. This is a third sentence.
    
  • Durch Abrufen einer Eigenschaft oder Aufrufen einer Methode, die eine Zeichenfolge zurückgibt. Im folgenden Beispiel werden die Methoden der String Klasse verwendet, um eine Teilzeichenfolge aus einer größeren Zeichenfolge zu extrahieren.

    string sentence = "This sentence has five words.";
    // Extract the second word.
    int startPosition = sentence.IndexOf(" ") + 1;
    string word2 = sentence.Substring(startPosition,
                                      sentence.IndexOf(" ", startPosition) - startPosition);
    Console.WriteLine("Second word: " + word2);
    // The example displays the following output:
    //       Second word: sentence
    
    let sentence = "This sentence has five words."
    // Extract the second word.
    let startPosition = sentence.IndexOf " " + 1
    let word2 = 
        sentence.Substring(startPosition, sentence.IndexOf(" ", startPosition) - startPosition)
    printfn $"Second word: {word2}"
    // The example displays the following output:
    //       Second word: sentence
    
    Dim sentence As String = "This sentence has five words."
    ' Extract the second word.
    Dim startPosition As Integer = sentence.IndexOf(" ") + 1
    Dim word2 As String = sentence.Substring(startPosition,
                                           sentence.IndexOf(" ", startPosition) - startPosition)
    Console.WriteLine("Second word: " + word2)
    ' The example displays the following output:
    '       Second word: sentence
    
  • Durch Aufrufen einer Formatierungsmethode zum Konvertieren eines Werts oder Objekts in die Zeichenfolgendarstellung. Im folgenden Beispiel wird das Zusammengesetztformatierungsfeature verwendet, um die Zeichenfolgendarstellung von zwei Objekten in eine Zeichenfolge einzubetten.

    DateTime dateAndTime = new DateTime(2011, 7, 6, 7, 32, 0);
    double temperature = 68.3;
    string result = String.Format("At {0:t} on {0:D}, the temperature was {1:F1} degrees Fahrenheit.",
                                  dateAndTime, temperature);
    Console.WriteLine(result);
    // The example displays the following output:
    //       At 7:32 AM on Wednesday, July 06, 2011, the temperature was 68.3 degrees Fahrenheit.
    
    let dateAndTime = DateTime(2011, 7, 6, 7, 32, 0)
    let temperature = 68.3
    String.Format("At {0:t} on {0:D}, the temperature was {1:F1} degrees Fahrenheit.", dateAndTime, temperature)
    |> printfn "%s"
    // The example displays the following output:
    //       At 7:32 AM on Wednesday, July 06, 2011, the temperature was 68.3 degrees Fahrenheit.
    
    Dim dateAndTime As DateTime = #07/06/2011 7:32:00AM#
    Dim temperature As Double = 68.3
    Dim result As String = String.Format("At {0:t} on {0:D}, the temperature was {1:F1} degrees Fahrenheit.",
                                       dateAndTime, temperature)
    Console.WriteLine(result)
    ' The example displays the following output:
    '       At 7:32 AM on Wednesday, July 06, 2011, the temperature was 68.3 degrees Fahrenheit.
    

Char-Objekte und Unicode-Zeichen

Jedes Zeichen in einer Zeichenfolge wird durch einen Unicode-Skalarwert definiert, der auch als Unicode-Codepunkt oder als Ordinalwert (numerisch) des Unicode-Zeichens bezeichnet wird. Jeder Codepunkt wird mithilfe der UTF-16-Codierung codiert, und der numerische Wert jedes Elements der Codierung wird durch ein Char Objekt dargestellt.

Hinweis

Beachten Sie, dass es möglich ist, ein Objekt zu erstellenString, das keine wohlgeformte Unicode-Zeichenfolge ist, da eine String Instanz aus einer sequenziellen Auflistung von UTF-16-Codeeinheiten besteht. Es ist z. B. möglich, eine Zeichenfolge zu erstellen, die einen niedrigen Ersatz ohne einen entsprechenden hohen Ersatz hat. Obwohl einige Methoden, z. B. die Methoden zum Codieren und Decodieren von Objekten im System.Text Namespace, überprüfungen ausführen können, um sicherzustellen, dass Zeichenfolgen wohlgeformt sind, String stellen Klassenmember nicht sicher, dass eine Zeichenfolge wohlgeformt ist.

Ein einzelnes Char Objekt stellt in der Regel einen einzelnen Codepunkt dar. Das heißt, der numerische Wert des Char Codes entspricht dem Codepunkt. Der Codepunkt für das Zeichen "a" lautet z. B. U+0061. Ein Codepunkt erfordert jedoch möglicherweise mehr als ein codiertes Element (mehrere Char Objekte). Der Unicode-Standard definiert zwei Zeichentypen, die mehreren Char Objekten entsprechen: Graphemen und Unicode-Zusatzcodepunkte, die Zeichen in den Unicode-Zusatzebenen entsprechen.

  • Ein Graphem wird durch ein Basiszeichen dargestellt, gefolgt von einem oder mehreren kombinierten Zeichen. Beispielsweise wird das Zeichen ä durch ein Char Objekt dargestellt, dessen Codepunkt U+0061 ist, gefolgt von einem Char Objekt, dessen Codepunkt U+0308 ist. Dieses Zeichen kann auch durch ein einzelnes Char Objekt definiert werden, das über einen Codepunkt von U+00E4 verfügt. Wie im folgenden Beispiel gezeigt, weist ein kultursensitiver Vergleich für die Gleichheit darauf hin, dass diese beiden Darstellungen gleich sind, obwohl ein gewöhnlicher Ordinalvergleich nicht erfolgt. Wenn die beiden Zeichenfolgen jedoch normalisiert sind, gibt ein Ordinalvergleich auch an, dass sie gleich sind. (Weitere Informationen zur Normalisierung von Zeichenfolgen finden Sie unter Normalisierungsabschnitt .)

    using System;
    using System.Globalization;
    using System.IO;
    
    public class Example5
    {
       public static void Main()
       {
          StreamWriter sw = new StreamWriter(@".\graphemes.txt");
          string grapheme = "\u0061\u0308";
          sw.WriteLine(grapheme);
          
          string singleChar = "\u00e4";
          sw.WriteLine(singleChar);
                
          sw.WriteLine("{0} = {1} (Culture-sensitive): {2}", grapheme, singleChar, 
                       String.Equals(grapheme, singleChar, 
                                     StringComparison.CurrentCulture));
          sw.WriteLine("{0} = {1} (Ordinal): {2}", grapheme, singleChar, 
                       String.Equals(grapheme, singleChar, 
                                     StringComparison.Ordinal));
          sw.WriteLine("{0} = {1} (Normalized Ordinal): {2}", grapheme, singleChar, 
                       String.Equals(grapheme.Normalize(), 
                                     singleChar.Normalize(), 
                                     StringComparison.Ordinal));
          sw.Close(); 
       }
    }
    // The example produces the following output:
    //       ä
    //       ä
    //       ä = ä (Culture-sensitive): True
    //       ä = ä (Ordinal): False
    //       ä = ä (Normalized Ordinal): True
    
    open System
    open System.IO
    
    do
        use sw = new StreamWriter(@".\graphemes.txt")
        let grapheme = "\u0061\u0308"
        sw.WriteLine grapheme
    
        let singleChar = "\u00e4"
        sw.WriteLine singleChar
    
        sw.WriteLine("{0} = {1} (Culture-sensitive): {2}", grapheme, singleChar, 
                    String.Equals(grapheme, singleChar,
                                    StringComparison.CurrentCulture))
        sw.WriteLine("{0} = {1} (Ordinal): {2}", grapheme, singleChar,
                    String.Equals(grapheme, singleChar,
                                    StringComparison.Ordinal))
        sw.WriteLine("{0} = {1} (Normalized Ordinal): {2}", grapheme, singleChar,
                    String.Equals(grapheme.Normalize(),
                                    singleChar.Normalize(),
                                    StringComparison.Ordinal))
    // The example produces the following output:
    //       ä
    //       ä
    //       ä = ä (Culture-sensitive): True
    //       ä = ä (Ordinal): False
    //       ä = ä (Normalized Ordinal): True
    
    Imports System.Globalization
    Imports System.IO
    
    Module Example9
        Public Sub Main()
            Dim sw As New StreamWriter(".\graphemes.txt")
            Dim grapheme As String = ChrW(&H61) + ChrW(&H308)
            sw.WriteLine(grapheme)
    
            Dim singleChar As String = ChrW(&HE4)
            sw.WriteLine(singleChar)
    
            sw.WriteLine("{0} = {1} (Culture-sensitive): {2}", grapheme, singleChar,
                       String.Equals(grapheme, singleChar,
                                     StringComparison.CurrentCulture))
            sw.WriteLine("{0} = {1} (Ordinal): {2}", grapheme, singleChar,
                       String.Equals(grapheme, singleChar,
                                     StringComparison.Ordinal))
            sw.WriteLine("{0} = {1} (Normalized Ordinal): {2}", grapheme, singleChar,
                       String.Equals(grapheme.Normalize(),
                                     singleChar.Normalize(),
                                     StringComparison.Ordinal))
            sw.Close()
        End Sub
    End Module
    ' The example produces the following output:
    '       ä
    '       ä
    '       ä = ä (Culture-sensitive): True
    '       ä = ä (Ordinal): False
    '       ä = ä (Normalized Ordinal): True
    
  • Ein zusätzlicher Unicode-Codepunkt (ein Ersatzpaar) wird durch ein Char Objekt dargestellt, dessen Codepunkt ein hoher Ersatz ist, gefolgt von einem Char Objekt, dessen Codepunkt ein niedriger Ersatz ist. Die Codeeinheiten von hohen Surrogaten reichen von U+D800 bis U+DBFF. Die Codeeinheiten niedriger Surrogate reichen von U+DC00 bis U+DFFF. Ersatzpaare werden verwendet, um Zeichen in den 16 Unicode-Zusatzebenen darzustellen. Im folgenden Beispiel wird ein Ersatzzeichen erstellt und an die Char.IsSurrogatePair(Char, Char) Methode übergeben, um zu bestimmen, ob es sich um ein Ersatzpaar handelt.

    string surrogate = "\uD800\uDC03";
    for (int ctr = 0; ctr < surrogate.Length; ctr++) 
       Console.Write($"U+{(ushort)surrogate[ctr]:X2} ");
    
    Console.WriteLine();
    Console.WriteLine("   Is Surrogate Pair: {0}", 
                      Char.IsSurrogatePair(surrogate[0], surrogate[1]));
    // The example displays the following output:
    //       U+D800 U+DC03
    //          Is Surrogate Pair: True
    
    open System
    
    let surrogate = "\uD800\uDC03"
    for i = 0 to surrogate.Length - 1 do
        printf $"U+{uint16 surrogate[i]:X2} "
    
    printfn $"\n   Is Surrogate Pair: {Char.IsSurrogatePair(surrogate[0], surrogate[1])}"
    // The example displays the following output:
    //       U+D800 U+DC03
    //          Is Surrogate Pair: True
    
    Module Example20
        Public Sub Main()
            Dim surrogate As String = ChrW(&HD800) + ChrW(&HDC03)
            For ctr As Integer = 0 To surrogate.Length - 1
                Console.Write("U+{0:X2} ", Convert.ToUInt16(surrogate(ctr)))
            Next
            Console.WriteLine()
            Console.WriteLine("   Is Surrogate Pair: {0}",
                            Char.IsSurrogatePair(surrogate(0), surrogate(1)))
        End Sub
    End Module
    
    ' The example displays the following output:
    '       U+D800 U+DC03
    '          Is Surrogate Pair: True
    

Der Unicode-Standard

Zeichen in einer Zeichenfolge werden durch UTF-16-codierte Codeeinheiten dargestellt, die Werten entsprechen Char .

Jedes Zeichen in einer Zeichenfolge weist eine zugeordnete Unicode-Zeichenkategorie auf, die in .NET durch die UnicodeCategory Enumeration dargestellt wird. Die Kategorie eines Zeichens oder eines Ersatzpaars kann durch Aufrufen der CharUnicodeInfo.GetUnicodeCategory Methode bestimmt werden.

.NET verwaltet eine eigene Tabelle von Zeichen und entsprechenden Kategorien. Dadurch wird sichergestellt, dass eine bestimmte Version einer .NET-Implementierung, die auf unterschiedlichen Plattformen ausgeführt wird, identische Informationen zu Zeichenkategorien zurückgibt. Auf allen .NET-Versionen und auf allen Betriebssystemplattformen werden Zeichenkategorieinformationen von der Unicode-Zeichendatenbank bereitgestellt.

Die folgende Tabelle enthält die .NET-Versionen und die Versionen des Unicode-Standards, auf dem ihre Zeichenkategorien basieren.

.NET-Version Version des Unicode-Standards
.NET Framework 1.1 The Unicode Standard, Version 4.0.0 (Der Unicode-Standard, Version 4.0.0)
.NET Framework 2.0 The Unicode Standard, Version 5.0.0 (Der Unicode-Standard, Version 5.0.0)
.NET Framework 3.5 The Unicode Standard, Version 5.0.0 (Der Unicode-Standard, Version 5.0.0)
.NET Framework 4 The Unicode Standard, Version 5.0.0 (Der Unicode-Standard, Version 5.0.0)
.NET Framework 4.5 The Unicode Standard, Version 6.3.0 (Der Unicode-Standard, Version 6.3.0)
.NET Framework 4.5.1 The Unicode Standard, Version 6.3.0 (Der Unicode-Standard, Version 6.3.0)
.NET Framework 4.5.2 The Unicode Standard, Version 6.3.0 (Der Unicode-Standard, Version 6.3.0)
.NET Framework 4.6 The Unicode Standard, Version 6.3.0 (Der Unicode-Standard, Version 6.3.0)
.NET Framework 4.6.1 The Unicode Standard, Version 6.3.0 (Der Unicode-Standard, Version 6.3.0)
.NET Framework 4.6.2 und höhere Versionen The Unicode Standard, Version 8.0.0 (Der Unicode-Standard, Version 8.0.0)
.NET Core 2.1 The Unicode Standard, Version 8.0.0 (Der Unicode-Standard, Version 8.0.0)
.NET Core 3.1 Unicode Standard, Version 11.0.0
.NET 5 Unicode Standard, Version 13.0.0

Darüber hinaus unterstützt .NET den Zeichenfolgenvergleich und die Sortierung basierend auf dem Unicode-Standard. Ab .NET Framework 4.5 unter Windows 8 und höheren Versionen des Windows-Betriebssystems delegiert die Laufzeit Zeichenfolgenvergleichs- und Sortiervorgänge an das Betriebssystem. Unter .NET Core und .NET 5+ werden Zeichenfolgenvergleichs- und Sortierungsinformationen von internationalen Komponenten für Unicode-Bibliotheken bereitgestellt (mit Ausnahme von Windows-Versionen vor Windows 10 Mai 2019 Update). In der folgenden Tabelle sind die Versionen von .NET und die Versionen des Unicode-Standards aufgeführt, auf denen der Zeichenvergleich und die Sortierung basieren.

.NET-Version Version des Unicode-Standards
.NET Framework 4.5 und höher unter Windows 7 The Unicode Standard, Version 5.0.0 (Der Unicode-Standard, Version 5.0.0)
.NET Framework 4.5 und höher unter Windows 8 und höher unter Windows-Betriebssystemen The Unicode Standard, Version 6.3.0 (Der Unicode-Standard, Version 6.3.0)
.NET Core und .NET 5 und höher Hängt von der Version des Unicode-Standards ab, die vom zugrunde liegenden Betriebssystem unterstützt wird.

Eingebettete Nullzeichen

In .NET kann ein String Objekt eingebettete NULL-Zeichen enthalten, die als Teil der Länge der Zeichenfolge zählen. In einigen Sprachen wie C und C++ gibt ein NULL-Zeichen jedoch das Ende einer Zeichenfolge an. sie wird nicht als Teil der Zeichenfolge betrachtet und wird nicht als Teil der Länge der Zeichenfolge gezählt. Dies bedeutet, dass die folgenden allgemeinen Annahmen, dass C- und C++-Programmierer oder Bibliotheken, die in C oder C++ geschrieben wurden, bei der Anwendung auf String Objekte nicht notwendigerweise gültig sind:

  • Der von den strlen Funktionen wcslen zurückgegebene Wert ist nicht unbedingt gleich String.Length.

  • Die von den strcpy_s Funktionen wcscpy_s erstellte Zeichenfolge ist nicht unbedingt identisch mit der Zeichenfolge, die von der String.Copy Methode erstellt wurde.

Sie sollten sicherstellen, dass systemeigener C- und C++-Code, der Objekte instanziiert String , und Code, der objekte über den Plattform-Aufruf übergeben String wird, nicht davon ausgeht, dass ein eingebettetes NULL-Zeichen das Ende der Zeichenfolge kennzeichnet.

Eingebettete NULL-Zeichen in einer Zeichenfolge werden auch anders behandelt, wenn eine Zeichenfolge sortiert (oder verglichen) und eine Zeichenfolge durchsucht wird. Nullzeichen werden ignoriert, wenn Kultursensible Vergleiche zwischen zwei Zeichenfolgen ausgeführt werden, einschließlich Vergleiche mithilfe der invarianten Kultur. Sie gelten nur für Ordinal- oder Groß-/Kleinschreibungsvergleiche. Andererseits werden eingebettete NULL-Zeichen beim Durchsuchen einer Zeichenfolge mit Methoden wie Contains, , StartsWithund IndexOf.

Zeichenfolgen und Indizes

Ein Index ist die Position eines Char Objekts (kein Unicode-Zeichen) in einem String. Ein Index ist eine nullbasierte, nichtnegative Zahl, die von der ersten Position in der Zeichenfolge beginnt, die Indexposition Null ist. Eine Reihe von Suchmethoden, z IndexOf . B. und LastIndexOf, geben den Index eines Zeichens oder einer Teilzeichenfolge in der Zeichenfolgeninstanz zurück.

Mit der Chars[] Eigenschaft können Sie auf einzelne Char Objekte anhand ihrer Indexposition in der Zeichenfolge zugreifen. Da es sich bei der Chars[] Eigenschaft um die Standardeigenschaft (in Visual Basic) oder den Indexer (in C# und F#) handelt, können Sie mithilfe von Code wie dem folgenden auf die einzelnen Char Objekte in einer Zeichenfolge zugreifen. Dieser Code sucht nach Leerzeichen oder Interpunktionszeichen in einer Zeichenfolge, um zu bestimmen, wie viele Wörter die Zeichenfolge enthält.

string s1 = "This string consists of a single short sentence.";
int nWords = 0;

s1 = s1.Trim();      
for (int ctr = 0; ctr < s1.Length; ctr++) {
   if (Char.IsPunctuation(s1[ctr]) | Char.IsWhiteSpace(s1[ctr]))
      nWords++;              
}
Console.WriteLine("The sentence\n   {0}\nhas {1} words.",
                  s1, nWords);                                                                     
// The example displays the following output:
//       The sentence
//          This string consists of a single short sentence.
//       has 8 words.
let s1 = "This string consists of a single short sentence."
let mutable nWords = 0

for i = 0 to s1.Length - 1 do
    if Char.IsPunctuation s1[i] || Char.IsWhiteSpace s1[i] then
        nWords <- nWords + 1
printfn $"The sentence\n   {s1}\nhas {nWords} words."
// The example displays the following output:
//       The sentence
//          This string consists of a single short sentence.
//       has 8 words.
Module Example12
    Public Sub Main()
        Dim s1 As String = "This string consists of a single short sentence."
        Dim nWords As Integer = 0

        s1 = s1.Trim()
        For ctr As Integer = 0 To s1.Length - 1
            If Char.IsPunctuation(s1(ctr)) Or Char.IsWhiteSpace(s1(ctr)) Then
                nWords += 1
            End If
        Next
        Console.WriteLine("The sentence{2}   {0}{2}has {1} words.",
                        s1, nWords, vbCrLf)
    End Sub
End Module
' The example displays the following output:
'       The sentence
'          This string consists of a single short sentence.
'       has 8 words.

Da die String Klasse die IEnumerable Schnittstelle implementiert, können Sie die Objekte in einer Zeichenfolge auch mithilfe eines foreach Konstrukts durchlaufenChar, wie im folgenden Beispiel gezeigt.

string s1 = "This string consists of a single short sentence.";
int nWords = 0;

s1 = s1.Trim();      
foreach (var ch in s1) {
   if (Char.IsPunctuation(ch) | Char.IsWhiteSpace(ch))
      nWords++;              
}
Console.WriteLine("The sentence\n   {0}\nhas {1} words.",
                  s1, nWords);                                                                     
// The example displays the following output:
//       The sentence
//          This string consists of a single short sentence.
//       has 8 words.
let s1 = "This string consists of a single short sentence."
let mutable nWords = 0

for ch in s1 do
    if Char.IsPunctuation ch || Char.IsWhiteSpace ch then
        nWords <- nWords + 1
printfn $"The sentence\n   {s1}\nhas {nWords} words."
// The example displays the following output:
//       The sentence
//          This string consists of a single short sentence.
//       has 8 words.
Module Example13
    Public Sub Main()
        Dim s1 As String = "This string consists of a single short sentence."
        Dim nWords As Integer = 0

        s1 = s1.Trim()
        For Each ch In s1
            If Char.IsPunctuation(ch) Or Char.IsWhiteSpace(ch) Then
                nWords += 1
            End If
        Next
        Console.WriteLine("The sentence{2}   {0}{2}has {1} words.",
                        s1, nWords, vbCrLf)
    End Sub
End Module
' The example displays the following output:
'       The sentence
'          This string consists of a single short sentence.
'       has 8 words.

Aufeinanderfolgende Indexwerte entsprechen möglicherweise nicht aufeinander folgenden Unicode-Zeichen, da ein Unicode-Zeichen möglicherweise als mehrere Char Objekte codiert werden kann. Insbesondere kann eine Zeichenfolge mehrstellige Texteinheiten enthalten, die durch ein Basiszeichen gebildet werden, gefolgt von einem oder mehreren kombinierten Zeichen oder durch Ersatzpaare. Verwenden Sie zum Arbeiten mit Unicode-Zeichen anstelle von Char Objekten die TextElementEnumeratorSystem.Globalization.StringInfo Klassen oder die String.EnumerateRunes Methode und die Rune Struktur. Das folgende Beispiel veranschaulicht den Unterschied zwischen Code, der mit Char Objekten und Code funktioniert, die mit Unicode-Zeichen funktionieren. Sie vergleicht die Anzahl der Zeichen oder Textelemente in jedem Wort eines Satzes. Die Zeichenfolge enthält zwei Sequenzen eines Basiszeichens, gefolgt von einem kombinierten Zeichen.

// First sentence of The Mystery of the Yellow Room, by Leroux.
string opening = "Ce n'est pas sans une certaine émotion que "+
                 "je commence à raconter ici les aventures " +
                 "extraordinaires de Joseph Rouletabille."; 
// Character counters.
int nChars = 0;
// Objects to store word count.
List<int> chars = new List<int>();
List<int> elements = new List<int>();

foreach (var ch in opening) {
   // Skip the ' character.
   if (ch == '\u0027') continue;
        
   if (Char.IsWhiteSpace(ch) | (Char.IsPunctuation(ch))) {
      chars.Add(nChars);
      nChars = 0;
   }
   else {
      nChars++;
   }
}

System.Globalization.TextElementEnumerator te = 
   System.Globalization.StringInfo.GetTextElementEnumerator(opening);
while (te.MoveNext()) {
   string s = te.GetTextElement();   
   // Skip the ' character.
   if (s == "\u0027") continue;
   if ( String.IsNullOrEmpty(s.Trim()) | (s.Length == 1 && Char.IsPunctuation(Convert.ToChar(s)))) {
      elements.Add(nChars);         
      nChars = 0;
   }
   else {
      nChars++;
   }
}

// Display character counts.
Console.WriteLine("{0,6} {1,20} {2,20}",
                  "Word #", "Char Objects", "Characters"); 
for (int ctr = 0; ctr < chars.Count; ctr++) 
   Console.WriteLine("{0,6} {1,20} {2,20}",
                     ctr, chars[ctr], elements[ctr]); 
// The example displays the following output:
//       Word #         Char Objects           Characters
//            0                    2                    2
//            1                    4                    4
//            2                    3                    3
//            3                    4                    4
//            4                    3                    3
//            5                    8                    8
//            6                    8                    7
//            7                    3                    3
//            8                    2                    2
//            9                    8                    8
//           10                    2                    1
//           11                    8                    8
//           12                    3                    3
//           13                    3                    3
//           14                    9                    9
//           15                   15                   15
//           16                    2                    2
//           17                    6                    6
//           18                   12                   12
open System
open System.Globalization

// First sentence of The Mystery of the Yellow Room, by Leroux.
let opening = "Ce n'est pas sans une certaine émotion que je commence à raconter ici les aventures extraordinaires de Joseph Rouletabille."
// Character counters.
let mutable nChars = 0
// Objects to store word count.
let chars = ResizeArray<int>()
let elements = ResizeArray<int>()

for ch in opening do
    // Skip the ' character.
    if ch <> '\u0027' then
        if Char.IsWhiteSpace ch || Char.IsPunctuation ch then
            chars.Add nChars
            nChars <- 0
        else
            nChars <- nChars + 1

let te = StringInfo.GetTextElementEnumerator opening
while te.MoveNext() do
    let s = te.GetTextElement()
    // Skip the ' character.
    if s <> "\u0027" then
        if String.IsNullOrEmpty(s.Trim()) || (s.Length = 1 && Char.IsPunctuation(Convert.ToChar s)) then
            elements.Add nChars
            nChars <- 0
        else
            nChars <- nChars + 1

// Display character counts.
printfn "%6s %20s %20s" "Word #" "Char Objects " "Characters"
for i = 0 to chars.Count - 1 do
    printfn "%6d %20d %20d" i chars[i] elements[i]
// The example displays the following output:
//       Word #         Char Objects           Characters
//            0                    2                    2
//            1                    4                    4
//            2                    3                    3
//            3                    4                    4
//            4                    3                    3
//            5                    8                    8
//            6                    8                    7
//            7                    3                    3
//            8                    2                    2
//            9                    8                    8
//           10                    2                    1
//           11                    8                    8
//           12                    3                    3
//           13                    3                    3
//           14                    9                    9
//           15                   15                   15
//           16                    2                    2
//           17                    6                    6
//           18                   12                   12
Imports System.Collections.Generic
Imports System.Globalization

Module Example14
    Public Sub Main()
        ' First sentence of The Mystery of the Yellow Room, by Leroux.
        Dim opening As String = "Ce n'est pas sans une certaine émotion que " +
                              "je commence à raconter ici les aventures " +
                              "extraordinaires de Joseph Rouletabille."
        ' Character counters.
        Dim nChars As Integer = 0
        ' Objects to store word count.
        Dim chars As New List(Of Integer)()
        Dim elements As New List(Of Integer)()

        For Each ch In opening
            ' Skip the ' character.
            If ch = ChrW(&H27) Then Continue For

            If Char.IsWhiteSpace(ch) Or Char.IsPunctuation(ch) Then
                chars.Add(nChars)
                nChars = 0
            Else
                nChars += 1
            End If
        Next

        Dim te As TextElementEnumerator = StringInfo.GetTextElementEnumerator(opening)
        Do While te.MoveNext()
            Dim s As String = te.GetTextElement()
            ' Skip the ' character.
            If s = ChrW(&H27) Then Continue Do
            If String.IsNullOrEmpty(s.Trim()) Or (s.Length = 1 AndAlso Char.IsPunctuation(Convert.ToChar(s))) Then
                elements.Add(nChars)
                nChars = 0
            Else
                nChars += 1
            End If
        Loop

        ' Display character counts.
        Console.WriteLine("{0,6} {1,20} {2,20}",
                        "Word #", "Char Objects", "Characters")
        For ctr As Integer = 0 To chars.Count - 1
            Console.WriteLine("{0,6} {1,20} {2,20}",
                           ctr, chars(ctr), elements(ctr))
        Next
    End Sub
End Module
' The example displays the following output:
'    Word #         Char Objects           Characters
'         0                    2                    2
'         1                    4                    4
'         2                    3                    3
'         3                    4                    4
'         4                    3                    3
'         5                    8                    8
'         6                    8                    7
'         7                    3                    3
'         8                    2                    2
'         9                    8                    8
'        10                    2                    1
'        11                    8                    8
'        12                    3                    3
'        13                    3                    3
'        14                    9                    9
'        15                   15                   15
'        16                    2                    2
'        17                    6                    6
'        18                   12                   12

In diesem Beispiel werden Textelemente mithilfe der StringInfo.GetTextElementEnumerator Methode und der TextElementEnumerator Klasse verwendet, um alle Textelemente in einer Zeichenfolge aufzählen zu können. Sie können auch ein Array abrufen, das den Anfangsindex jedes Textelements enthält, indem Sie die StringInfo.ParseCombiningCharacters Methode aufrufen.

Weitere Informationen zum Arbeiten mit Texteinheiten anstelle einzelner Char Werte finden Sie unter Einführung in die Zeichencodierung in .NET.

NULL-Zeichenfolgen und leere Zeichenfolgen

Eine Zeichenfolge, die deklariert wurde, aber keinem Wert zugewiesen wurde, ist null. Beim Versuch, Methoden für diese Zeichenfolge aufzurufen, wird ein NullReferenceException. Eine NULL-Zeichenfolge unterscheidet sich von einer leeren Zeichenfolge, bei der es sich um eine Zeichenfolge handelt, deren Wert "" oder String.Empty". In einigen Fällen löst das Übergeben einer NULL-Zeichenfolge oder einer leeren Zeichenfolge als Argument in einem Methodenaufruf eine Ausnahme aus. Wenn Sie beispielsweise eine NULL-Zeichenfolge an die Int32.Parse Methode übergeben, wird ein ArgumentNullException, und das Übergeben einer leeren Zeichenfolge löst eine FormatException. In anderen Fällen kann ein Methodenargument entweder eine NULL-Zeichenfolge oder eine leere Zeichenfolge sein. Wenn Sie beispielsweise eine IFormattable Implementierung für eine Klasse bereitstellen, möchten Sie sowohl eine NULL-Zeichenfolge als auch eine leere Zeichenfolge mit dem allgemeinen Formatbezeichner ("G") gleichsetzen.

Die String Klasse enthält die folgenden beiden Komfortmethoden, mit denen Sie testen können, ob eine Zeichenfolge oder leer ist null :

  • IsNullOrEmpty, der angibt, ob eine Zeichenfolge gleich null ist oder gleich String.Emptyist. Diese Methode beseitigt die Notwendigkeit, Code wie die folgenden zu verwenden:

    if (str == null || str.Equals(String.Empty))
    
    if str = null || str.Equals String.Empty then
    
    If str Is Nothing OrElse str.Equals(String.Empty) Then
    
  • IsNullOrWhiteSpace, das angibt, ob eine Zeichenfolge gleich String.Emptyist nulloder ausschließlich aus Leerzeichen besteht. Diese Methode beseitigt die Notwendigkeit, Code wie die folgenden zu verwenden:

    if (str == null || str.Equals(String.Empty) || str.Trim().Equals(String.Empty))
    
    if str = null || str.Equals String.Empty || str.Trim().Equals String.Empty then
    
    If str Is Nothing OrElse str.Equals(String.Empty) OrElse str.Trim().Equals(String.Empty) Then
    

Im folgenden Beispiel wird die IsNullOrEmpty Methode in der IFormattable.ToString Implementierung einer benutzerdefinierten Temperature Klasse verwendet. Die Methode unterstützt die Formatzeichenfolgen "G", "C", "F" und "K". Wenn eine leere Formatzeichenfolge oder eine Formatzeichenfolge, deren Wert an die Methode übergeben wird null , wird der Wert in die Formatzeichenfolge "G" geändert.

public string ToString(string format, IFormatProvider provider) 
{
   if (String.IsNullOrEmpty(format)) format = "G";  
   if (provider == null) provider = CultureInfo.CurrentCulture;
   
   switch (format.ToUpperInvariant())
   {
      // Return degrees in Celsius.    
      case "G":
      case "C":
         return temp.ToString("F2", provider) + "°C";
      // Return degrees in Fahrenheit.
      case "F": 
         return (temp * 9 / 5 + 32).ToString("F2", provider) + "°F";
      // Return degrees in Kelvin.
      case "K":   
         return (temp + 273.15).ToString();
      default:
         throw new FormatException(
               String.Format("The {0} format string is not supported.", 
                             format));
   }                                   
}
member _.ToString(format: string, provider: IFormatProvider) =
    let format = 
        if String.IsNullOrEmpty format then "G" else format
    
    let provider: IFormatProvider = 
        if provider = null then CultureInfo.CurrentCulture else provider

    match format.ToUpperInvariant() with
    // Return degrees in Celsius.
    | "G"
    | "C" ->
        temp.ToString("F2", provider) + "°C"
    // Return degrees in Fahrenheit.
    | "F" ->
        (temp * 9. / 5. + 32.).ToString("F2", provider) + "°F"
    // Return degrees in Kelvin.
    | "K" ->
        (temp + 273.15).ToString()
    | _ ->
        raise (FormatException(String.Format("The {0} format string is not supported.",format)))
Public Overloads Function ToString(fmt As String, provider As IFormatProvider) As String _
               Implements IFormattable.ToString
    If String.IsNullOrEmpty(fmt) Then fmt = "G"
    If provider Is Nothing Then provider = CultureInfo.CurrentCulture

    Select Case fmt.ToUpperInvariant()
     ' Return degrees in Celsius.    
        Case "G", "C"
            Return temp.ToString("F2", provider) + "°C"
     ' Return degrees in Fahrenheit.
        Case "F"
            Return (temp * 9 / 5 + 32).ToString("F2", provider) + "°F"
     ' Return degrees in Kelvin.
        Case "K"
            Return (temp + 273.15).ToString()
        Case Else
            Throw New FormatException(
              String.Format("The {0} format string is not supported.",
                            fmt))
    End Select
End Function

Unveränderlichkeit und die StringBuilder-Klasse

Ein String Objekt wird als unveränderlich (schreibgeschützt) bezeichnet, da sein Wert nach seiner Erstellung nicht mehr geändert werden kann. Methoden, die scheinbar ein String Objekt ändern, geben tatsächlich ein neues String Objekt zurück, das die Änderung enthält.

Da Zeichenfolgen unveränderlich sind, können Zeichenfolgenmanipulationsroutinen, die wiederholte Hinzufügungen oder Löschungen ausführen, was als einzelne Zeichenfolge angezeigt wird, eine erhebliche Leistungseinbußen erfüllen. Der folgende Code verwendet beispielsweise einen Zufallszahlengenerator, um eine Zeichenfolge mit 1000 Zeichen im Bereich zu erstellen, die 0x0001, um 0x052F. Obwohl der Code scheinbar eine Zeichenfolgenverkettung verwendet, um ein neues Zeichen an die vorhandene Zeichenfolge mit dem Namen stranzufügen, erstellt er tatsächlich ein neues String Objekt für jeden Verkettungsvorgang.

using System;
using System.IO;
using System.Text;

public class Example6
{
   public static void Main()
   {
      Random rnd = new Random();
      
      string str = String.Empty;
      StreamWriter sw = new StreamWriter(@".\StringFile.txt", 
                           false, Encoding.Unicode);

      for (int ctr = 0; ctr <= 1000; ctr++) {
         str += (char)rnd.Next(1, 0x0530);
         if (str.Length % 60 == 0)
            str += Environment.NewLine;          
      }                    
      sw.Write(str);
      sw.Close();
   }
}
open System
open System.IO
open System.Text

do
    let rnd = Random()

    let mutable str = String.Empty
    use sw = new StreamWriter(@".\StringFile.txt", false, Encoding.Unicode)
    for _ = 0 to 1000 do
        str <- str + (rnd.Next(1, 0x0530) |> char |> string)
        if str.Length % 60 = 0 then
            str <- str + Environment.NewLine
    sw.Write str
Imports System.IO
Imports System.Text

Module Example10
    Public Sub Main()
        Dim rnd As New Random()

        Dim str As String = String.Empty
        Dim sw As New StreamWriter(".\StringFile.txt",
                           False, Encoding.Unicode)

        For ctr As Integer = 0 To 1000
            str += ChrW(rnd.Next(1, &H530))
            If str.Length Mod 60 = 0 Then str += vbCrLf
        Next
        sw.Write(str)
        sw.Close()
    End Sub
End Module

Sie können die StringBuilder Klasse anstelle der String Klasse für Vorgänge verwenden, die mehrere Änderungen am Wert einer Zeichenfolge vornehmen. Im Gegensatz zu Instanzen der String Klasse StringBuilder können Objekte stummgeschaltet werden. Wenn Sie Teilzeichenfolgen aus einer Zeichenfolge verketten, anfügen oder löschen, werden die Vorgänge für eine einzelne Zeichenfolge ausgeführt. Wenn Sie den Wert eines StringBuilder Objekts geändert haben, können Sie dessen StringBuilder.ToString Methode aufrufen, um ihn in eine Zeichenfolge zu konvertieren. Im folgenden Beispiel wird das String im vorherigen Beispiel verwendete Zeichen ersetzt, um 1000 zufällige Zeichen im Bereich zu verketten, um mit einem StringBuilder Objekt 0x0001 zu 0x052F.

using System;
using System.IO;
using System.Text;

public class Example10
{
   public static void Main()
   {
      Random rnd = new Random();
      StringBuilder sb = new StringBuilder();
      StreamWriter sw = new StreamWriter(@".\StringFile.txt", 
                                         false, Encoding.Unicode);

      for (int ctr = 0; ctr <= 1000; ctr++) {
         sb.Append((char)rnd.Next(1, 0x0530));
         if (sb.Length % 60 == 0)
            sb.AppendLine();          
      }                    
      sw.Write(sb.ToString());
      sw.Close();
   }
}
open System
open System.IO
open System.Text

do
    let rnd = Random()
    let sb = StringBuilder()
    use sw = new StreamWriter(@".\StringFile.txt", false, Encoding.Unicode)

    for _ = 0 to 1000 do
        sb.Append(rnd.Next(1, 0x0530) |> char) |> ignore
        if sb.Length % 60 = 0 then
            sb.AppendLine() |> ignore
    sw.Write(string sb)
Imports System.IO
Imports System.Text

Module Example11
    Public Sub Main()
        Dim rnd As New Random()
        Dim sb As New StringBuilder()
        Dim sw As New StreamWriter(".\StringFile.txt",
                                 False, Encoding.Unicode)

        For ctr As Integer = 0 To 1000
            sb.Append(ChrW(rnd.Next(1, &H530)))
            If sb.Length Mod 60 = 0 Then sb.AppendLine()
        Next
        sw.Write(sb.ToString())
        sw.Close()
    End Sub
End Module

Ordnungs- und Kultursensible Vorgänge

Member der String Klasse führen entweder Ordinal- oder Kultursensible (linguistische) Operationen für ein String Objekt aus. Ein Ordinalvorgang dient dem numerischen Wert jedes Char Objekts. Ein kulturabhängiger Vorgang wirkt auf den Wert des String Objekts und berücksichtigt kulturspezifische Groß-/Kleinschreibung, Sortierung, Formatierung und Analyseregeln. Kultursensible Vorgänge werden im Kontext einer explizit deklarierten Kultur oder der impliziten aktuellen Kultur ausgeführt. Die beiden Arten von Vorgängen können sehr unterschiedliche Ergebnisse erzeugen, wenn sie für dieselbe Zeichenfolge ausgeführt werden.

.NET unterstützt auch Kultur-insensitive Zeichenfolgenoperationen mithilfe der invarianten Kultur (CultureInfo.InvariantCulture), die lose auf den Kultureinstellungen der englischen Sprache basiert, die unabhängig von der Region ist. Im Gegensatz zu anderen System.Globalization.CultureInfo Einstellungen werden die Einstellungen der invarianten Kultur garantiert auf einem einzelnen Computer, von System zu System und in allen Versionen von .NET konsistent Standard. Die invariante Kultur kann als eine Art black box gesehen werden, die stabilität von Zeichenfolgenvergleichen und Sortierungen in allen Kulturen gewährleistet.

Wichtig

Wenn Ihre Anwendung eine Sicherheitsentscheidung über einen symbolischen Bezeichner wie z. B. einen Dateinamen oder eine benannte Pipe oder über gespeicherte Daten wie die textbasierten Daten in einer XML-Datei trifft, sollte der Vorgang einen Ordinalvergleich anstelle eines kultursensiblen Vergleichs verwenden. Dies liegt daran, dass ein kultursensibler Vergleich je nach tatsächlicher Kultur unterschiedliche Ergebnisse liefern kann, während ein Ordinalvergleich ausschließlich vom Binären Wert der verglichenen Zeichen abhängt.

Wichtig

Die meisten Methoden, die Zeichenfolgenvorgänge ausführen, enthalten eine Überladung mit einem Parameter vom Typ StringComparison, mit dem Sie angeben können, ob die Methode einen Ordinal- oder Kulturvorgang ausführt. Im Allgemeinen sollten Sie diese Überladung aufrufen, um die Absicht des Methodenaufrufs klar zu machen. Bewährte Methoden und Anleitungen für die Verwendung von Ordnungs- und Kultursensiblen Vorgängen für Zeichenfolgen finden Sie unter Bewährte Methoden für die Verwendung von Zeichenfolgen.

Vorgänge für Groß- und Kleinschreibung, Analyse und Formatierung, Vergleich und Sortierung sowie Tests auf Gleichheit können entweder ordinal oder kulturempfindlich sein. In den folgenden Abschnitten werden die einzelnen Vorgangskategorien erläutert.

Tipp

Sie sollten immer eine Methodenüberladung aufrufen, die die Absicht des Methodenaufrufs klar macht. Anstatt beispielsweise die Compare(String, String) Methode aufzurufen, um einen kultursensitiven Vergleich von zwei Zeichenfolgen mithilfe der Konventionen der aktuellen Kultur durchzuführen, sollten Sie die Compare(String, String, StringComparison) Methode mit dem Wert für StringComparison.CurrentCulture das comparisonType Argument aufrufen. Weitere Informationen finden Sie unter Empfohlene Vorgehensweisen für die Verwendung von Zeichenfolgen in .NET Framework.

Sie können die Sortiergewichtungstabellen, eine Reihe von Textdateien, die Informationen zu den Zeichenstärken enthalten, die in Sortier- und Vergleichsvorgängen verwendet werden, aus den folgenden Links herunterladen:

Schreibweise

Groß-/Kleinschreibungsregeln bestimmen, wie die Groß-/Kleinschreibung eines Unicode-Zeichens geändert wird; Beispiel: von Kleinbuchstaben in Großbuchstaben. Häufig wird vor einem Zeichenfolgenvergleich ein Groß-/Kleinschreibungsvorgang ausgeführt. Beispielsweise kann eine Zeichenfolge in Großbuchstaben konvertiert werden, sodass sie mit einer anderen Großbuchstabenzeichenfolge verglichen werden kann. Sie können die Zeichen in einer Zeichenfolge in Kleinbuchstaben konvertieren, indem Sie die ToLower Methode aufrufen ToLowerInvariant , und Sie können sie durch Aufrufen der ToUpper Methode ToUpperInvariant in Großbuchstaben konvertieren. Darüber hinaus können Sie die TextInfo.ToTitleCase Methode verwenden, um eine Zeichenfolge in Titelbuchstaben zu konvertieren.

Hinweis

Gilt nur für .NET Core unter Linux- und macOS-Systemen: Das Sortierverhalten für die C- und Posix-Kulturen unterscheidet immer zwischen Groß- und Kleinschreibung, weil diese Kulturen nicht die erwartete Unicode-Sortierreihenfolge verwenden. Bei der Durchführung kulturrelevanter Sortiervorgänge ohne Unterscheidung von Groß-/Kleinschreibung wird empfohlen, eine andere Kultur als C oder Posix zu verwenden.

Groß-/Kleinschreibungen können auf den Regeln der aktuellen Kultur, einer bestimmten Kultur oder der invarianten Kultur basieren. Da Fallzuordnungen je nach verwendeter Kultur variieren können, kann das Ergebnis von Groß-/Kleinschreibungsvorgängen je nach Kultur variieren. Die tatsächlichen Unterschiede bei der Groß-/Kleinschreibung sind von drei Arten:

  • Unterschiede in der Fallzuordnung von LATIN CAPITAL LETTER I (U+0049), LATIN SMALL LETTER I (U+0069), LATIN CAPITAL LETTER I WITH DOT ABOVE (U+0130) und LATIN SMALL LETTER DOTLESS I (U+0131). In den Kulturen tr-TR (Türkei) und az-Latn-AZ (Aserbaidschan, Lateinisch) und in den Kulturen tr, az und az-Latn ist das Kleinbuchstabenäquivalent DES LATEINISCHEN KLEINBUCHSTABENS I LATEINISCHER KLEINBUCHSTABEN DOTLESS I, und die Großbuchstaben-Entsprechung des LATEINISCHEN KLEINBUCHSTABENS I ist LATEINISCHER GROßBUCHSTABE I MIT PUNKT ÜBER. In allen anderen Kulturen, einschließlich der invarianten Kultur, sind LATIN SMALL LETTER I und LATIN CAPITAL LETTER I Kleinbuchstaben I Kleinbuchstaben und Großbuchstaben Äquivalente.

    Im folgenden Beispiel wird veranschaulicht, wie ein Zeichenfolgenvergleich zur Verhinderung des Dateisystemzugriffs fehlschlagen kann, wenn er auf einen Kultursensiblen Groß-/Kleinschreibungsvergleich basiert. (Die Groß-/Kleinschreibungskonventionen der invarianten Kultur sollten verwendet werden.)

    using System;
    using System.Globalization;
    using System.Threading;
    
    public class Example1
    {
       const string disallowed = "file";
       
       public static void Main()
       {
          IsAccessAllowed(@"FILE:\\\c:\users\user001\documents\FinancialInfo.txt");
       }
    
       private static void IsAccessAllowed(String resource)
       {
          CultureInfo[] cultures = { CultureInfo.CreateSpecificCulture("en-US"),
                                     CultureInfo.CreateSpecificCulture("tr-TR") };
          String scheme = null;
          int index = resource.IndexOfAny( new Char[] { '\\', '/' } );
          if (index > 0) 
             scheme = resource.Substring(0, index - 1);
    
          // Change the current culture and perform the comparison.
          foreach (var culture in cultures) {
             Thread.CurrentThread.CurrentCulture = culture;
             Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName);
             Console.WriteLine(resource);
             Console.WriteLine("Access allowed: {0}", 
                               ! String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase));      
             Console.WriteLine();
          }   
       }
    }
    // The example displays the following output:
    //       Culture: English (United States)
    //       FILE:\\\c:\users\user001\documents\FinancialInfo.txt
    //       Access allowed: False
    //       
    //       Culture: Turkish (Turkey)
    //       FILE:\\\c:\users\user001\documents\FinancialInfo.txt
    //       Access allowed: True
    
    open System
    open System.Globalization
    open System.Threading
    
    let disallowed = "file"
    
    let isAccessAllowed (resource: string) =
        let cultures = 
            [| CultureInfo.CreateSpecificCulture "en-US"
               CultureInfo.CreateSpecificCulture "tr-TR" |]
        let index = resource.IndexOfAny [| '\\'; '/' |]
        let scheme =
            if index > 0 then
                resource.Substring(0, index - 1)
            else 
                null
    
        // Change the current culture and perform the comparison.
        for culture in cultures do
            Thread.CurrentThread.CurrentCulture <- culture
            printfn $"Culture: {CultureInfo.CurrentCulture.DisplayName}"
            printfn $"{resource}"
            printfn $"Access allowed: {String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase) |> not}"
            printfn ""
            
    isAccessAllowed @"FILE:\\\c:\users\user001\documents\FinancialInfo.txt"
    // The example displays the following output:
    //       Culture: English (United States)
    //       FILE:\\\c:\users\user001\documents\FinancialInfo.txt
    //       Access allowed: False
    //
    //       Culture: Turkish (Turkey)
    //       FILE:\\\c:\users\user001\documents\FinancialInfo.txt
    //       Access allowed: True
    
    Imports System.Globalization
    Imports System.Threading
    
    Module Example2
        Const disallowed = "file"
    
        Public Sub Main()
            IsAccessAllowed("FILE:\\\c:\users\user001\documents\FinancialInfo.txt")
        End Sub
    
        Private Sub IsAccessAllowed(resource As String)
            Dim cultures() As CultureInfo = {CultureInfo.CreateSpecificCulture("en-US"),
                                            CultureInfo.CreateSpecificCulture("tr-TR")}
            Dim scheme As String = Nothing
            Dim index As Integer = resource.IndexOfAny({"\"c, "/"c})
            If index > 0 Then scheme = resource.Substring(0, index - 1)
    
            ' Change the current culture and perform the comparison.
            For Each culture In cultures
                Thread.CurrentThread.CurrentCulture = culture
                Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
                Console.WriteLine(resource)
                Console.WriteLine("Access allowed: {0}",
                               Not String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase))
                Console.WriteLine()
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       Culture: English (United States)
    '       FILE:\\\c:\users\user001\documents\FinancialInfo.txt
    '       Access allowed: False
    '       
    '       Culture: Turkish (Turkey)
    '       FILE:\\\c:\users\user001\documents\FinancialInfo.txt
    '       Access allowed: True
    
  • Unterschiede bei Fallzuordnungen zwischen der invarianten Kultur und allen anderen Kulturen. In diesen Fällen gibt die Verwendung der Groß-/Kleinschreibungsregeln der invarianten Kultur, um ein Zeichen in Groß- oder Kleinbuchstaben zu ändern, dasselbe Zeichen zurück. Für alle anderen Kulturen gibt sie einen anderen Charakter zurück. Einige der betroffenen Zeichen sind in der folgenden Tabelle aufgeführt.

    Zeichen Wenn geändert in Gibt zurück
    MICRON-ZEICHEN (U+00B5) Großbuchstaben GRIECHISCHER GROßBUCHSTABE MU (U+-39C)
    LATEINISCHER GROßBUCHSTABE I MIT PUNKT OBEN (U+0130) Kleinbuchstaben KLEINER LATEINISCHER BUCHSTABE I (U+0069)
    KLEINER LATEINISCHER BUCHSTABE DOTLESS I (U+0131) Großbuchstaben LATEINISCHER BUCHSTABE I (U+0049)
    KLEINER LATEINISCHER BUCHSTABE LONG S (U+017F) Großbuchstaben LATEINISCHER GROßBUCHSTABE S (U+0053)
    LATEINISCHER GROßBUCHSTABE D MIT KLEINEM BUCHSTABEN Z MIT CARON (U+01C5) Kleinbuchstaben KLEINER LATEINISCHER BUCHSTABE DZ MIT CARON (U+01C6)
    KOMBINIEREN DES GRIECHISCHEN YPOGEGRAMMENI (U+0345) Großbuchstaben GRIECHISCHER GROßBUCHSTABE IOTA (U+0399)
  • Unterschiede bei der Fallzuordnung von Zwei-Buchstaben-Gemischt-Groß-/Kleinschreibungspaaren im ASCII-Zeichenbereich. In den meisten Kulturen ist ein Zwei-Buchstaben-Gemischt-Groß-/Kleinschreibungspaar gleich dem äquivalenten Zwei-Buchstaben-Groß- oder Kleinbuchstabepaar. Dies gilt nicht für die folgenden Zwei-Buchstaben-Paare in den folgenden Kulturen, da sie in jedem Fall mit einem Digraph verglichen werden:

    • "lJ" und "nJ" in der Kultur hr-HR (Kroatisch (Kroatien)).
    • "cH" in den Kulturen cs-CZ (Tschechische Republik)) und sk-SK (Slowakei).
    • "aA" in der Da-DK -Kultur (Dänemark).
    • "cS", "dZ", "dZS", "nY", "sZ", "tY" und "zS" in der Hu-HU(Ungarn)-Kultur.
    • "cH" und "lL" in der es-ES_tradnl (Spanisch (Spanien, traditionelle Sortierung))-Kultur.
    • "cH", "gI", "kH", "nG" "nH", "pH", "qU', "tH" und "tR" in der Vi-VN (Vietnam)-Kultur.

    Es ist jedoch ungewöhnlich, auf eine Situation zu stoßen, in der ein kultursensibler Vergleich dieser Paare Probleme verursacht, da diese Paare in festen Zeichenfolgen oder Bezeichnern ungewöhnlich sind.

Im folgenden Beispiel werden einige der Unterschiede bei der Groß-/Kleinschreibung zwischen Kulturen beim Konvertieren von Zeichenfolgen in Großbuchstaben veranschaulicht.

using System;
using System.Globalization;
using System.IO;

public class Example
{
   public static void Main()
   {
      StreamWriter sw = new StreamWriter(@".\case.txt");   
      string[] words = { "file", "sıfır", "Dženana" };
      CultureInfo[] cultures = { CultureInfo.InvariantCulture, 
                                 new CultureInfo("en-US"),  
                                 new CultureInfo("tr-TR") };

      foreach (var word in words) {
         sw.WriteLine("{0}:", word);
         foreach (var culture in cultures) {
            string name = String.IsNullOrEmpty(culture.Name) ? 
                                 "Invariant" : culture.Name;
            string upperWord = word.ToUpper(culture);
            sw.WriteLine("   {0,10}: {1,7} {2, 38}", name, 
                         upperWord, ShowHexValue(upperWord));
         }
         sw.WriteLine();  
      }
      sw.Close();
   }

   private static string ShowHexValue(string s)
   {
      string retval = null;
      foreach (var ch in s) {
         byte[] bytes = BitConverter.GetBytes(ch);
         retval += String.Format("{0:X2} {1:X2} ", bytes[1], bytes[0]);     
      }
      return retval;
   } 
}
// The example displays the following output:
//    file:
//        Invariant:    FILE               00 46 00 49 00 4C 00 45 
//            en-US:    FILE               00 46 00 49 00 4C 00 45 
//            tr-TR:    FİLE               00 46 01 30 00 4C 00 45 
//    
//    sıfır:
//        Invariant:   SıFıR         00 53 01 31 00 46 01 31 00 52 
//            en-US:   SIFIR         00 53 00 49 00 46 00 49 00 52 
//            tr-TR:   SIFIR         00 53 00 49 00 46 00 49 00 52 
//    
//    Dženana:
//        Invariant:  DžENANA   01 C5 00 45 00 4E 00 41 00 4E 00 41 
//            en-US:  DŽENANA   01 C4 00 45 00 4E 00 41 00 4E 00 41 
//            tr-TR:  DŽENANA   01 C4 00 45 00 4E 00 41 00 4E 00 41
open System
open System.Globalization
open System.IO

let showHexValue (s: string) =
    let mutable retval = ""
    for ch in s do
        let bytes = BitConverter.GetBytes ch
        retval <- retval + String.Format("{0:X2} {1:X2} ", bytes[1], bytes[0])
    retval

do
    use sw = new StreamWriter(@".\case.txt")
    let words = [| "file"; "sıfır"; "Dženana" |]
    let cultures = 
        [| CultureInfo.InvariantCulture 
           CultureInfo "en-US"
           CultureInfo "tr-TR" |]

    for word in words do
        sw.WriteLine("{0}:", word)
        for culture in cultures do
            let name =
                 if String.IsNullOrEmpty culture.Name then "Invariant" else culture.Name
            let upperWord = word.ToUpper culture
            sw.WriteLine("   {0,10}: {1,7} {2, 38}", name, upperWord, showHexValue upperWord)
        sw.WriteLine()
    sw.Close()

// The example displays the following output:
//    file:
//        Invariant:    FILE               00 46 00 49 00 4C 00 45
//            en-US:    FILE               00 46 00 49 00 4C 00 45
//            tr-TR:    FİLE               00 46 01 30 00 4C 00 45
//
//    sıfır:
//        Invariant:   SıFıR         00 53 01 31 00 46 01 31 00 52
//            en-US:   SIFIR         00 53 00 49 00 46 00 49 00 52
//            tr-TR:   SIFIR         00 53 00 49 00 46 00 49 00 52
//
//    Dženana:
//        Invariant:  DžENANA   01 C5 00 45 00 4E 00 41 00 4E 00 41
//            en-US:  DŽENANA   01 C4 00 45 00 4E 00 41 00 4E 00 41
//            tr-TR:  DŽENANA   01 C4 00 45 00 4E 00 41 00 4E 00 41
Imports System.Globalization
Imports System.IO

Module Example1
    Public Sub Main()
        Dim sw As New StreamWriter(".\case.txt")
        Dim words As String() = {"file", "sıfır", "Dženana"}
        Dim cultures() As CultureInfo = {CultureInfo.InvariantCulture,
                                        New CultureInfo("en-US"),
                                        New CultureInfo("tr-TR")}

        For Each word In words
            sw.WriteLine("{0}:", word)
            For Each culture In cultures
                Dim name As String = If(String.IsNullOrEmpty(culture.Name),
                                 "Invariant", culture.Name)
                Dim upperWord As String = word.ToUpper(culture)
                sw.WriteLine("   {0,10}: {1,7} {2, 38}", name,
                         upperWord, ShowHexValue(upperWord))

            Next
            sw.WriteLine()
        Next
        sw.Close()
    End Sub

    Private Function ShowHexValue(s As String) As String
        Dim retval As String = Nothing
        For Each ch In s
            Dim bytes() As Byte = BitConverter.GetBytes(ch)
            retval += String.Format("{0:X2} {1:X2} ", bytes(1), bytes(0))
        Next
        Return retval
    End Function
End Module
' The example displays the following output:
'    file:
'        Invariant:    FILE               00 46 00 49 00 4C 00 45 
'            en-US:    FILE               00 46 00 49 00 4C 00 45 
'            tr-TR:    FİLE               00 46 01 30 00 4C 00 45 
'    
'    sıfır:
'        Invariant:   SıFıR         00 53 01 31 00 46 01 31 00 52 
'            en-US:   SIFIR         00 53 00 49 00 46 00 49 00 52 
'            tr-TR:   SIFIR         00 53 00 49 00 46 00 49 00 52 
'    
'    Dženana:
'        Invariant:  DžENANA   01 C5 00 45 00 4E 00 41 00 4E 00 41 
'            en-US:  DŽENANA   01 C4 00 45 00 4E 00 41 00 4E 00 41 
'            tr-TR:  DŽENANA   01 C4 00 45 00 4E 00 41 00 4E 00 41

Analysieren und Formatieren

Formatierung und Analyse sind umgekehrte Vorgänge. Formatierungsregeln bestimmen, wie ein Wert, z. B. ein Datum und eine Uhrzeit oder eine Zahl, in seine Zeichenfolgendarstellung konvertiert wird, während analyseregeln bestimmen, wie eine Zeichenfolgendarstellung in einen Wert wie Datum und Uhrzeit konvertiert werden soll. Sowohl Formatierungs- als auch Analyseregeln sind von kulturellen Konventionen abhängig. Im folgenden Beispiel wird die Mehrdeutigkeit veranschaulicht, die beim Interpretieren einer kulturspezifischen Datumszeichenfolge auftreten kann. Ohne die Konventionen der Kultur zu kennen, die zur Erstellung einer Datumszeichenfolge verwendet wurde, ist es nicht möglich zu wissen, ob der 03.01.2011, der 01.03.2011 und der 01.03.2011 den 3. Januar 2011 oder den 1. März 2011 darstellen.

using System;
using System.Globalization;

public class Example9
{
   public static void Main()
   {
      DateTime date = new DateTime(2011, 3, 1);
      CultureInfo[] cultures = { CultureInfo.InvariantCulture, 
                                 new CultureInfo("en-US"), 
                                 new CultureInfo("fr-FR") };

      foreach (var culture in cultures)
         Console.WriteLine("{0,-12} {1}", String.IsNullOrEmpty(culture.Name) ?
                           "Invariant" : culture.Name, 
                           date.ToString("d", culture));                                    
   }
}
// The example displays the following output:
//       Invariant    03/01/2011
//       en-US        3/1/2011
//       fr-FR        01/03/2011
open System
open System.Globalization

let date = DateTime(2011, 3, 1)
let cultures = 
      [| CultureInfo.InvariantCulture
         CultureInfo "en-US"
         CultureInfo "fr-FR" |]

for culture in cultures do
    printfn $"""{(if String.IsNullOrEmpty culture.Name then "Invariant" else culture.Name),-12} {date.ToString("d", culture)}"""
// The example displays the following output:
//       Invariant    03/01/2011
//       en-US        3/1/2011
//       fr-FR        01/03/2011
Imports System.Globalization

Module Example8
    Public Sub Main()
        Dim dat As Date = #3/1/2011#
        Dim cultures() As CultureInfo = {CultureInfo.InvariantCulture,
                                        New CultureInfo("en-US"),
                                        New CultureInfo("fr-FR")}

        For Each culture In cultures
            Console.WriteLine("{0,-12} {1}", If(String.IsNullOrEmpty(culture.Name),
                           "Invariant", culture.Name),
                           dat.ToString("d", culture))
        Next
    End Sub
End Module
' The example displays the following output:
'       Invariant    03/01/2011
'       en-US        3/1/2011
'       fr-FR        01/03/2011

Ähnlich wie im folgenden Beispiel gezeigt kann eine einzelne Zeichenfolge je nach Kultur, deren Konventionen im Analysevorgang verwendet werden, unterschiedliche Datumsangaben erzeugen.

using System;
using System.Globalization;

public class Example15
{
   public static void Main()
   {
      string dateString = "07/10/2011";
      CultureInfo[] cultures = { CultureInfo.InvariantCulture, 
                                 CultureInfo.CreateSpecificCulture("en-GB"), 
                                 CultureInfo.CreateSpecificCulture("en-US") };
      Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}\n", "Date String", "Culture", 
                                                 "Month", "Day");
      foreach (var culture in cultures) {
         DateTime date = DateTime.Parse(dateString, culture);
         Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}", dateString, 
                           String.IsNullOrEmpty(culture.Name) ?
                           "Invariant" : culture.Name, 
                           date.Month, date.Day);
      }                      
   }
}
// The example displays the following output:
//       Date String     Culture    Month      Day
//       
//       07/10/2011    Invariant        7       10
//       07/10/2011        en-GB       10        7
//       07/10/2011        en-US        7       10
open System
open System.Globalization

let dateString = "07/10/2011"
let cultures = 
    [| CultureInfo.InvariantCulture
       CultureInfo.CreateSpecificCulture "en-GB"
       CultureInfo.CreateSpecificCulture "en-US" |]
printfn $"""{"Date String",-12} {"Culture",10} {"Month",8} {"Day",8}\n"""
for culture in cultures do
    let date = DateTime.Parse(dateString, culture)
    printfn $"""{dateString,-12} {(if String.IsNullOrEmpty culture.Name then "Invariant" else culture.Name),10} {date.Month,8} {date.Day,8}"""
// The example displays the following output:
//       Date String     Culture    Month      Day
//
//       07/10/2011    Invariant        7       10
//       07/10/2011        en-GB       10        7
//       07/10/2011        en-US        7       10
Imports System.Globalization

Module Example18
    Public Sub Main()
        Dim dateString As String = "07/10/2011"
        Dim cultures() As CultureInfo = {CultureInfo.InvariantCulture,
                                        CultureInfo.CreateSpecificCulture("en-GB"),
                                        CultureInfo.CreateSpecificCulture("en-US")}
        Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}", "Date String", "Culture",
                                                 "Month", "Day")
        Console.WriteLine()
        For Each culture In cultures
            Dim dat As Date = DateTime.Parse(dateString, culture)
            Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}", dateString,
                           If(String.IsNullOrEmpty(culture.Name),
                           "Invariant", culture.Name),
                           dat.Month, dat.Day)
        Next
    End Sub
End Module
' The example displays the following output:
'       Date String     Culture    Month      Day
'       
'       07/10/2011    Invariant        7       10
'       07/10/2011        en-GB       10        7
'       07/10/2011        en-US        7       10

Zeichenfolgenvergleich und -sortierung

Konventionen zum Vergleichen und Sortieren von Zeichenfolgen variieren von Kultur zu Kultur. Die Sortierreihenfolge kann beispielsweise auf Phonetik oder auf der visuellen Darstellung von Zeichen basieren. In ostasiatischen Sprachen werden Zeichen anhand der Anzahl der Striche und der Radikale der Ideogramme sortiert. Die Sortierung hängt außerdem von der Reihenfolge ab, die das Alphabet der jeweiligen Sprache bzw. Kultur aufweist. Im Dänischen gibt es beispielsweise das Zeichen "Æ", das im Alphabet nach dem Zeichen "Z" einsortiert ist. Darüber hinaus können Vergleiche zwischen Groß- und Kleinschreibung unterschieden werden, und Groß-/Kleinschreibungsregeln können sich je nach Kultur unterscheiden. Ordinalvergleich verwendet dagegen beim Vergleichen und Sortieren von Zeichenfolgen die Unicode-Codepunkte einzelner Zeichen in einer Zeichenfolge.

Sortierregeln bestimmen die alphabetische Reihenfolge von Unicode-Zeichen und wie zwei Zeichenfolgen miteinander verglichen werden. Die Methode vergleicht beispielsweise String.Compare(String, String, StringComparison) zwei Zeichenfolgen basierend auf dem StringComparison Parameter. Wenn der Parameterwert lautet StringComparison.CurrentCulture, führt die Methode einen linguistischen Vergleich aus, der die Konventionen der aktuellen Kultur verwendet. Wenn der Parameterwert lautet StringComparison.Ordinal, führt die Methode einen Ordinalvergleich aus. Wenn es sich bei der aktuellen Kultur also um US-Englisch handelt, betrachtet der erste Aufruf der String.Compare(String, String, StringComparison) Methode (mit kultursensitivem Vergleich) "a" kleiner als "A", aber der zweite Aufruf der gleichen Methode (unter Verwendung des Ordinalvergleichs) betrachtet "a" größer als "A".

using System;
using System.Globalization;
using System.Threading;

public class Example2
{
   public static void Main()
   {
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
      Console.WriteLine(String.Compare("A", "a", StringComparison.CurrentCulture));
      Console.WriteLine(String.Compare("A", "a", StringComparison.Ordinal));
   }
}
// The example displays the following output:
//       1
//       -32
open System
open System.Globalization
open System.Threading

Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-US"
printfn $"""{String.Compare("A", "a", StringComparison.CurrentCulture)}"""
printfn $"""{String.Compare("A", "a", StringComparison.Ordinal)}"""
// The example displays the following output:
//       1
//       -32
Imports System.Globalization
Imports System.Threading

Module Example3
    Public Sub Main()
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
        Console.WriteLine(String.Compare("A", "a", StringComparison.CurrentCulture))
        Console.WriteLine(String.Compare("A", "a", StringComparison.Ordinal))
    End Sub
End Module
' The example displays the following output:
'       1                                                                                     
'       -32

.NET unterstützt Wort-, Zeichenfolgen- und Ordnungsregeln:

  • Bei einer Wortsortierung wird ein kulturabhängiger Vergleich von Zeichenfolgen durchgeführt, bei dem bestimmten nicht alphanumerischen Unicode-Zeichen u. U. bestimmte Gewichtungen zugeordnet sind. Der Bindestrich (-) kann z. B. ein sehr kleines Gewicht zugewiesen haben, sodass "coop" und "co-op" nebeneinander in einer sortierten Liste angezeigt werden. Eine Liste der String Methoden, die zwei Zeichenfolgen mithilfe von Wortsortierregeln vergleichen, finden Sie im Abschnitt "Zeichenfolgenvorgänge nach Kategorie ".

  • Eine Zeichenfolgensortierung führt auch einen kulturabhängigen Vergleich durch. Es ähnelt einer Wortsortierung, mit der Ausnahme, dass es keine Sonderfälle gibt, und alle nichtalphanumerischen Symbole kommen vor allen alphanumerischen Unicode-Zeichen. Zwei Zeichenfolgen können mithilfe von Zeichenfolgensortierregeln verglichen werden, indem die Methodenüberladungen aufgerufen werden, die CompareInfo.Compare einen options Parameter aufweisen, der einen Wert von CompareOptions.StringSort. Beachten Sie, dass dies die einzige Methode ist, die .NET bereitstellt, um zwei Zeichenfolgen mithilfe von Zeichenfolgensortierungsregeln zu vergleichen.

  • Eine Ordinalsortierung vergleicht Zeichenfolgen anhand des numerischen Werts jedes Char-Objekts in der Zeichenfolge. Bei einem Ordinalvergleich wird die Groß-/Kleinschreibung automatisch beachtet, da die Klein- und Großbuchstaben eines Zeichens unterschiedliche Codepunkte aufweisen. Wenn der Fall jedoch nicht wichtig ist, können Sie einen Ordinalvergleich angeben, der die Groß-/Kleinschreibung ignoriert. Dies entspricht der Konvertierung der Zeichenfolge in Großbuchstaben mithilfe der invarianten Kultur und anschließendem Durchführen eines Ordinalvergleichs für das Ergebnis. Eine Liste der String Methoden, die zwei Zeichenfolgen mithilfe von Ordnungsregeln vergleichen, finden Sie im Abschnitt "Zeichenfolgenvorgänge nach Kategorie ".

Ein kultursensitiver Vergleich ist jeder Vergleich, der explizit oder implizit ein CultureInfo Objekt verwendet, einschließlich der invarianten Kultur, die von der CultureInfo.InvariantCulture Eigenschaft angegeben wird. Die implizite Kultur ist die aktuelle Kultur, die durch die und CultureInfo.CurrentCulture die Thread.CurrentCulture Eigenschaften angegeben wird. Die Sortierreihenfolge von alphabetischen Zeichen (d. h. Zeichen, für die die Char.IsLetter Eigenschaft zurückgegeben wird true) gibt es in verschiedenen Kulturen erhebliche Abweichungen. Sie können einen kultursensitiven Vergleich angeben, der die Konventionen einer bestimmten Kultur verwendet, indem Sie ein CultureInfo Objekt an eine Zeichenfolgenvergleichsmethode wie z Compare(String, String, CultureInfo, CompareOptions). B. angeben. Sie können einen kultursensiblen Vergleich angeben, der die Konventionen der aktuellen Kultur verwendet, indem StringComparison.CurrentCultureStringComparison.CurrentCultureIgnoreCaseSie eine andere Enumeration als CompareOptions.Ordinal oder ein beliebiges Element der CompareOptions Aufzählung bereitstellen oder CompareOptions.OrdinalIgnoreCase eine entsprechende Überladung der Compare Methode vornehmen. Ein kultursensibler Vergleich eignet sich im Allgemeinen für die Sortierung, während ein Ordinalvergleich nicht erfolgt. Ein Ordinalvergleich ist in der Regel geeignet, um zu bestimmen, ob zwei Zeichenfolgen gleich sind (d. h. zum Ermitteln der Identität), während ein kultursensibler Vergleich nicht der Richtige ist.

Im folgenden Beispiel wird der Unterschied zwischen kultursensitiver und ordinaler Vergleich veranschaulicht. Im Beispiel werden drei Zeichenfolgen ausgewertet, "Apple", "Æble" und "AEble", wobei ordinaler Vergleich und die Konventionen der Da-DK- und en-US-Kulturen verwendet werden (jede davon ist die Standardkultur zum Zeitpunkt des Aufrufs der Compare Methode). Da die dänische Sprache das Zeichen "Æ" als einzelner Buchstabe behandelt und nach "Z" im Alphabet sortiert, ist die Zeichenfolge "Æble" größer als "Apple". "Æble" wird jedoch nicht als Äquivalent zu "AEble" betrachtet, daher ist "Æble" auch größer als "AEble". Die en-US-Kultur enthält nicht den Buchstaben "Æ", sondern behandelt ihn als Äquivalent zu "AE", was erklärt, warum "Æble" kleiner als "Apple" ist, aber gleich "AEble". Ordinalvergleich betrachtet dagegen "Apple" als kleiner als "Æble", und "Æble" ist größer als "AEble".

using System;
using System.Globalization;
using System.Threading;

public class CompareStringSample
{
   public static void Main()
   {
      string str1 = "Apple";
      string str2 = "Æble"; 
      string str3 = "AEble";
      
      // Set the current culture to Danish in Denmark.
      Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");
      Console.WriteLine("Current culture: {0}", 
                        CultureInfo.CurrentCulture.Name);
      Console.WriteLine("Comparison of {0} with {1}: {2}", 
                        str1, str2, String.Compare(str1, str2));
      Console.WriteLine("Comparison of {0} with {1}: {2}\n", 
                        str2, str3, String.Compare(str2, str3));
      
      // Set the current culture to English in the U.S.
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine("Current culture: {0}", 
                        CultureInfo.CurrentCulture.Name);
      Console.WriteLine("Comparison of {0} with {1}: {2}", 
                        str1, str2, String.Compare(str1, str2));
      Console.WriteLine("Comparison of {0} with {1}: {2}\n", 
                        str2, str3, String.Compare(str2, str3));
      
      // Perform an ordinal comparison.
      Console.WriteLine("Ordinal comparison");
      Console.WriteLine("Comparison of {0} with {1}: {2}", 
                        str1, str2, 
                        String.Compare(str1, str2, StringComparison.Ordinal));
      Console.WriteLine("Comparison of {0} with {1}: {2}", 
                        str2, str3, 
                        String.Compare(str2, str3, StringComparison.Ordinal));
   }
}
// The example displays the following output:
//       Current culture: da-DK
//       Comparison of Apple with Æble: -1
//       Comparison of Æble with AEble: 1
//       
//       Current culture: en-US
//       Comparison of Apple with Æble: 1
//       Comparison of Æble with AEble: 0
//       
//       Ordinal comparison
//       Comparison of Apple with Æble: -133
//       Comparison of Æble with AEble: 133
open System
open System.Globalization
open System.Threading

let str1 = "Apple"
let str2 = "Æble"
let str3 = "AEble"

// Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture <- CultureInfo "da-DK"
printfn $"Current culture: {CultureInfo.CurrentCulture.Name}"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n"

// Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture <- CultureInfo "en-US"
printfn $"Current culture: {CultureInfo.CurrentCulture.Name}"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n"

// Perform an ordinal comparison.
printfn "Ordinal comparison"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2, StringComparison.Ordinal)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3, StringComparison.Ordinal)}"
// The example displays the following output:
//       Current culture: da-DK
//       Comparison of Apple with Æble: -1
//       Comparison of Æble with AEble: 1
//
//       Current culture: en-US
//       Comparison of Apple with Æble: 1
//       Comparison of Æble with AEble: 0
//
//       Ordinal comparison
//       Comparison of Apple with Æble: -133
//       Comparison of Æble with AEble: 133
Imports System.Globalization
Imports System.Threading

Public Module Example6
    Public Sub Main()
        Dim str1 As String = "Apple"
        Dim str2 As String = "Æble"
        Dim str3 As String = "AEble"

        ' Set the current culture to Danish in Denmark.
        Thread.CurrentThread.CurrentCulture = New CultureInfo("da-DK")
        Console.WriteLine("Current culture: {0}",
                        CultureInfo.CurrentCulture.Name)
        Console.WriteLine("Comparison of {0} with {1}: {2}",
                        str1, str2, String.Compare(str1, str2))
        Console.WriteLine("Comparison of {0} with {1}: {2}",
                        str2, str3, String.Compare(str2, str3))
        Console.WriteLine()

        ' Set the current culture to English in the U.S.
        Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
        Console.WriteLine("Current culture: {0}",
                        CultureInfo.CurrentCulture.Name)
        Console.WriteLine("Comparison of {0} with {1}: {2}",
                        str1, str2, String.Compare(str1, str2))
        Console.WriteLine("Comparison of {0} with {1}: {2}",
                        str2, str3, String.Compare(str2, str3))
        Console.WriteLine()

        ' Perform an ordinal comparison.
        Console.WriteLine("Ordinal comparison")
        Console.WriteLine("Comparison of {0} with {1}: {2}",
                        str1, str2,
                        String.Compare(str1, str2, StringComparison.Ordinal))
        Console.WriteLine("Comparison of {0} with {1}: {2}",
                        str2, str3,
                        String.Compare(str2, str3, StringComparison.Ordinal))
    End Sub
End Module
' The example displays the following output:
'       Current culture: da-DK
'       Comparison of Apple with Æble: -1
'       Comparison of Æble with AEble: 1
'       
'       Current culture: en-US
'       Comparison of Apple with Æble: 1
'       Comparison of Æble with AEble: 0
'       
'       Ordinal comparison
'       Comparison of Apple with Æble: -133
'       Comparison of Æble with AEble: 133

Verwenden Sie die folgenden allgemeinen Richtlinien, um eine geeignete Sortier- oder Zeichenfolgenvergleichsmethode auszuwählen:

  • Wenn die Zeichenfolgen basierend auf der Kultur des Benutzers sortiert werden sollen, sollten Sie sie basierend auf den Konventionen der aktuellen Kultur sortieren. Wenn sich die Kultur des Benutzers ändert, ändert sich auch die Reihenfolge sortierter Zeichenfolgen entsprechend. Beispielsweise sollte eine Thesaurusanwendung immer Wörter basierend auf der Kultur des Benutzers sortieren.

  • Wenn die Zeichenfolgen basierend auf den Konventionen einer bestimmten Kultur sortiert werden sollen, sollten Sie sie sortieren, indem Sie ein CultureInfo Objekt angeben, das diese Kultur einer Vergleichsmethode darstellt. Beispielsweise soll in einer Anwendung, die Schüler/Studenten eine bestimmte Sprache vermittelt, Zeichenfolgen basierend auf den Konventionen einer der Kulturen sortiert werden, die diese Sprache sprechen.

  • Wenn die Reihenfolge der Zeichenfolgen in allen Kulturen unverändert Standard sein soll, sollten Sie sie basierend auf den Konventionen der invarianten Kultur sortieren oder einen Ordinalvergleich verwenden. Beispielsweise würden Sie eine Ordnungssortierung verwenden, um die Namen von Dateien, Prozessen, Mutexes oder benannten Rohren zu organisieren.

  • Für einen Vergleich, der eine Sicherheitsentscheidung umfasst (z. B. ob ein Benutzername gültig ist), sollten Sie immer einen Ordinaltest für die Gleichheit durchführen, indem Sie eine Überladung der Equals Methode aufrufen.

Hinweis

Die kultursensiblen Sortier- und Groß-/Kleinschreibungsregeln, die im Zeichenfolgenvergleich verwendet werden, hängen von der Version von .NET ab. Bei .NET Core hängt der Zeichenfolgenvergleich von der Vom zugrunde liegenden Betriebssystem unterstützten Version des Unicode-Standards ab. In .NET Framework 4.5 und höheren Versionen, die unter Windows 8 oder höher ausgeführt werden, entsprechen Sortier-, Schreib-, Normalisierungs- und Unicode-Zeicheninformationen dem Unicode 6.0-Standard. Auf anderen Windows-Betriebssystemen entsprechen sie dem Unicode 5.0-Standard.

Weitere Informationen zu Wort-, Zeichenfolgen- und Ordnungsregeln finden Sie im System.Globalization.CompareOptions Thema. Weitere Empfehlungen für die Verwendung der einzelnen Regeln finden Sie unter Bewährte Methoden für die Verwendung von Zeichenfolgen.

Normalerweise rufen Sie keine Zeichenfolgenvergleichsmethoden auf, z Compare . B. direkt, um die Sortierreihenfolge von Zeichenfolgen zu bestimmen. Stattdessen werden Vergleichsmethoden durch Sortiermethoden wie Array.Sort z. B. oder List<T>.Sort. Im folgenden Beispiel werden vier verschiedene Sortiervorgänge (Wortsortierung mithilfe der aktuellen Kultur, der Wortsortierung mithilfe der invarianten Kultur, der Ordinalsortierung und der Zeichenfolgensortierung mithilfe der invarianten Kultur) ausgeführt, ohne explizit eine Zeichenfolgenvergleichsmethode aufzurufen, obwohl sie den zu verwendenden Vergleichstyp angeben. Beachten Sie, dass jeder Sortiertyp eine eindeutige Sortierreihenfolge von Zeichenfolgen in seinem Array erzeugt.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
 
public class Example3
{
   public static void Main()
   {
      string[] strings = { "coop", "co-op", "cooperative", 
                           "co\u00ADoperative", "cœur", "coeur" };

      // Perform a word sort using the current (en-US) culture.
      string[] current = new string[strings.Length]; 
      strings.CopyTo(current, 0); 
      Array.Sort(current, StringComparer.CurrentCulture);

      // Perform a word sort using the invariant culture.
      string[] invariant = new string[strings.Length];
      strings.CopyTo(invariant, 0); 
      Array.Sort(invariant, StringComparer.InvariantCulture);

      // Perform an ordinal sort.
      string[] ordinal = new string[strings.Length];
      strings.CopyTo(ordinal, 0); 
      Array.Sort(ordinal, StringComparer.Ordinal);

      // Perform a string sort using the current culture.
      string[] stringSort = new string[strings.Length];
      strings.CopyTo(stringSort, 0); 
      Array.Sort(stringSort, new SCompare());

      // Display array values
      Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}\n", 
                        "Original", "Word Sort", "Invariant Word", 
                        "Ordinal Sort", "String Sort");
      for (int ctr = 0; ctr < strings.Length; ctr++)
         Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}", 
                           strings[ctr], current[ctr], invariant[ctr], 
                           ordinal[ctr], stringSort[ctr] );          
   }
}

// IComparer<String> implementation to perform string sort.
internal class SCompare : IComparer<String>
{
   public int Compare(string x, string y)
   {
      return CultureInfo.CurrentCulture.CompareInfo.Compare(x, y, CompareOptions.StringSort);
   }
}
// The example displays the following output:
//         Original     Word Sort  Invariant Word  Ordinal Sort   String Sort
//    
//             coop          cœur            cœur         co-op         co-op
//            co-op         coeur           coeur         coeur          cœur
//      cooperative          coop            coop          coop         coeur
//     co­operative         co-op           co-op   cooperative          coop
//             cœur   cooperative     cooperative  co­operative   cooperative
//            coeur  co­operative    co­operative          cœur  co­operative
open System
open System.Collections.Generic
open System.Globalization

// IComparer<String> implementation to perform string sort using an F# object expression.
let scompare = 
    { new IComparer<String> with
        member _.Compare(x, y) =
            CultureInfo.CurrentCulture.CompareInfo.Compare(x, y, CompareOptions.StringSort) }

let strings = [| "coop"; "co-op"; "cooperative"; "co\u00ADoperative"; "cœur"; "coeur" |]

// Perform a word sort using the current (en-US) culture.
let current = Array.copy strings
Array.Sort(current, StringComparer.CurrentCulture)

// Perform a word sort using the invariant culture.
let invariant = Array.copy strings
Array.Sort(invariant, StringComparer.InvariantCulture)

// Perform an ordinal sort.
let ordinal = Array.copy strings
Array.Sort(ordinal, StringComparer.Ordinal)

// Perform a string sort using the current culture.
let stringSort = Array.copy strings
Array.Sort(stringSort, scompare)

// Display array values
printfn "%13s %13s %15s %13s %13s\n" "Original" "Word Sort" "Invariant Word" "Ordinal Sort" "String Sort"
for i = 0 to strings.Length - 1 do
    printfn "%13s %13s %15s %13s %13s\n" strings[i] current[i] invariant[i] ordinal[i] stringSort[i]

// The example displays the following output:
//         Original     Word Sort  Invariant Word  Ordinal Sort   String Sort
//
//             coop          cœur            cœur         co-op         co-op
//            co-op         coeur           coeur         coeur          cœur
//      cooperative          coop            coop          coop         coeur
//     co­operative         co-op           co-op   cooperative          coop
//             cœur   cooperative     cooperative  co­operative   cooperative
//            coeur  co­operative    co­operative          cœur  co­operative
Imports System.Collections
Imports System.Collections.Generic
Imports System.Globalization

Module Example4
    Public Sub Main()
        Dim strings() As String = {"coop", "co-op", "cooperative",
                                  "co" + ChrW(&HAD) + "operative",
                                  "cœur", "coeur"}

        ' Perform a word sort using the current (en-US) culture.
        Dim current(strings.Length - 1) As String
        strings.CopyTo(current, 0)
        Array.Sort(current, StringComparer.CurrentCulture)

        ' Perform a word sort using the invariant culture.
        Dim invariant(strings.Length - 1) As String
        strings.CopyTo(invariant, 0)
        Array.Sort(invariant, StringComparer.InvariantCulture)

        ' Perform an ordinal sort.
        Dim ordinal(strings.Length - 1) As String
        strings.CopyTo(ordinal, 0)
        Array.Sort(ordinal, StringComparer.Ordinal)

        ' Perform a string sort using the current culture.
        Dim stringSort(strings.Length - 1) As String
        strings.CopyTo(stringSort, 0)
        Array.Sort(stringSort, New SCompare())

        ' Display array values
        Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}",
                        "Original", "Word Sort", "Invariant Word",
                        "Ordinal Sort", "String Sort")
        Console.WriteLine()

        For ctr As Integer = 0 To strings.Length - 1
            Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}",
                           strings(ctr), current(ctr), invariant(ctr),
                           ordinal(ctr), stringSort(ctr))
        Next
    End Sub
End Module

' IComparer<String> implementation to perform string sort.
Friend Class SCompare : Implements IComparer(Of String)
   Public Function Compare(x As String, y As String) As Integer _
                   Implements IComparer(Of String).Compare
      Return CultureInfo.CurrentCulture.CompareInfo.Compare(x, y, CompareOptions.StringSort)
   End Function
End Class
' The example displays the following output:
'         Original     Word Sort  Invariant Word  Ordinal Sort   String Sort
'    
'             coop          cœur            cœur         co-op         co-op
'            co-op         coeur           coeur         coeur          cœur
'      cooperative          coop            coop          coop         coeur
'     co­operative         co-op           co-op   cooperative          coop
'             cœur   cooperative     cooperative  co­operative   cooperative
'            coeur  co­operative    co­operative          cœur  co­operative

Tipp

Intern verwendet .NET Sortierschlüssel, um einen kulturell sensiblen Zeichenfolgenvergleich zu unterstützen. Jedem Zeichen in einer Zeichenfolge sind mehrere Sortiergewichtungskategorien zugeordnet, darunter nach Skript, alphabetischer Folge, Groß-/Kleinschreibung und diakritischer Gewichtung. Ein durch die SortKey Klasse dargestellter Sortierschlüssel stellt ein Repository dieser Gewichtungen für eine bestimmte Zeichenfolge bereit. Wenn Ihre App eine große Anzahl von Such- oder Sortiervorgängen für dieselbe Gruppe von Zeichenfolgen ausführt, können Sie die Leistung verbessern, indem Sie Sortierschlüssel für alle von ihr verwendeten Zeichenfolgen generieren und speichern. Wenn ein Sortier- oder Vergleichsvorgang erforderlich ist, verwenden Sie die Sortierschlüssel anstelle der Zeichenfolgen. Weitere Informationen finden Sie in den Ausführungen zur SortKey-Klasse.

Wenn Sie keine Zeichenfolgenvergleichskonvention angeben, werden Sortiermethoden wie Array.Sort(Array) z. B. eine kulturabhängige Sortierung zwischen Groß- und Kleinschreibung für Zeichenfolgen ausgeführt. Im folgenden Beispiel wird veranschaulicht, wie sich das Ändern der aktuellen Kultur auf die Reihenfolge sortierter Zeichenfolgen in einem Array auswirkt. Es erstellt ein Array von drei Zeichenfolgen. Zuerst wird die System.Threading.Thread.CurrentThread.CurrentCulture-Eigenschaft auf "en-US" festgelegt, und die Array.Sort(Array)-Methode wird aufgerufen. Die sich daraus ergebende Sortierreihenfolge basiert auf den Sortierkonventionen für die Kultur Englisch (USA). Als Nächstes wird die System.Threading.Thread.CurrentThread.CurrentCulture-Eigenschaft auf "da-DK" festgelegt und die Array.Sort-Methode erneut aufgerufen. Die sich daraus ergebende Sortierreihenfolge unterscheidet sich von den Ergebnissen für "en-US", da die Sortierkonventionen für "Dänisch (Dänemark)" verwendet werden.

using System;
using System.Globalization;
using System.Threading;

public class ArraySort
{
   public static void Main(String[] args)
   {
      // Create and initialize a new array to store the strings.
      string[] stringArray = { "Apple", "Æble", "Zebra"};

      // Display the values of the array.
      Console.WriteLine( "The original string array:");
      PrintIndexAndValues(stringArray);

      // Set the CurrentCulture to "en-US".
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      // Sort the values of the array.
      Array.Sort(stringArray);

      // Display the values of the array.
      Console.WriteLine("After sorting for the culture \"en-US\":");
      PrintIndexAndValues(stringArray);

      // Set the CurrentCulture to "da-DK".
      Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");
      // Sort the values of the Array.
      Array.Sort(stringArray);

      // Display the values of the array.
      Console.WriteLine("After sorting for the culture \"da-DK\":");
      PrintIndexAndValues(stringArray);
   }
   public static void PrintIndexAndValues(string[] myArray)
   {
      for (int i = myArray.GetLowerBound(0); i <=
            myArray.GetUpperBound(0); i++ )
         Console.WriteLine("[{0}]: {1}", i, myArray[i]);
      Console.WriteLine();
   }
}
// The example displays the following output:
//       The original string array:
//       [0]: Apple
//       [1]: Æble
//       [2]: Zebra
//
//       After sorting for the "en-US" culture:
//       [0]: Æble
//       [1]: Apple
//       [2]: Zebra
//
//       After sorting for the culture "da-DK":
//       [0]: Apple
//       [1]: Zebra
//       [2]: Æble
open System
open System.Globalization
open System.Threading

let printIndexAndValues (myArray: string[]) =
    for i = myArray.GetLowerBound 0 to myArray.GetUpperBound 0 do
        printfn $"[{i}]: {myArray[i]}" 
    printfn ""

// Create and initialize a new array to store the strings.
let stringArray = [| "Apple"; "Æble"; "Zebra" |]

// Display the values of the array.
printfn "The original string array:"
printIndexAndValues stringArray

// Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture <- CultureInfo "en-US"
// Sort the values of the array.
Array.Sort stringArray

// Display the values of the array.
printfn "After sorting for the culture \"en-US\":"
printIndexAndValues stringArray

// Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture <- CultureInfo "da-DK"
// Sort the values of the Array.
Array.Sort stringArray

// Display the values of the array.
printfn "After sorting for the culture \"da-DK\":"
printIndexAndValues stringArray
// The example displays the following output:
//       The original string array:
//       [0]: Apple
//       [1]: Æble
//       [2]: Zebra
//
//       After sorting for the "en-US" culture:
//       [0]: Æble
//       [1]: Apple
//       [2]: Zebra
//
//       After sorting for the culture "da-DK":
//       [0]: Apple
//       [1]: Zebra
//       [2]: Æble
Imports System.Globalization
Imports System.IO
Imports System.Threading

Public Class TextToFile   
   Public Shared Sub Main()
      ' Creates and initializes a new array to store 
      ' these date/time objects.
      Dim stringArray() As String = { "Apple", "Æble", "Zebra"}
      
      ' Displays the values of the array.
      Console.WriteLine("The original string array:")
      PrintIndexAndValues(stringArray)
      
      ' Set the CurrentCulture to "en-US".
      Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
      ' Sort the values of the Array.
      Array.Sort(stringArray)
      
      ' Display the values of the array.
      Console.WriteLine("After sorting for the ""en-US"" culture:")
      PrintIndexAndValues(stringArray)
      
      ' Set the CurrentCulture to "da-DK".
      Thread.CurrentThread.CurrentCulture = New CultureInfo("da-DK")
      ' Sort the values of the Array.
      Array.Sort(stringArray)
      
      ' Displays the values of the Array.
      Console.WriteLine("After sorting for the culture ""da-DK"":")
      PrintIndexAndValues(stringArray)
   End Sub

   Public Shared Sub PrintIndexAndValues(myArray() As String)
      For i As Integer = myArray.GetLowerBound(0) To myArray.GetUpperBound(0)
         Console.WriteLine("[{0}]: {1}", i, myArray(i))
      Next
      Console.WriteLine()
   End Sub 
End Class
' The example displays the following output:
'       The original string array:
'       [0]: Apple
'       [1]: Æble
'       [2]: Zebra
'       
'       After sorting for the "en-US" culture:
'       [0]: Æble
'       [1]: Apple
'       [2]: Zebra
'       
'       After sorting for the culture "da-DK":
'       [0]: Apple
'       [1]: Zebra
'       [2]: Æble

Warnung

Wenn Der hauptzweck beim Vergleichen von Zeichenfolgen darin besteht, zu bestimmen, ob sie gleich sind, sollten Sie die String.Equals Methode aufrufen. In der Regel sollten Equals Sie einen Ordinalvergleich durchführen. Die String.Compare Methode soll in erster Linie Zeichenfolgen sortieren.

Zeichenfolgensuchmethoden wie String.StartsWith und String.IndexOf, können auch Kultursensible oder Ordinalzeichenfolgenvergleiche durchführen. Im folgenden Beispiel werden die Unterschiede zwischen Ordinal- und Kultursensitiven Vergleichen mithilfe der IndexOf Methode veranschaulicht. Eine kultursensible Suche, bei der die aktuelle Kultur Englisch (USA) ist, betrachtet die Teilzeichenfolge "oe" mit der Ligatur "œ". Da ein weicher Bindestrich (U+00AD) ein Zeichen der Nullbreite ist, behandelt die Suche den weichen Bindestrich als Äquivalent zu String.Empty und findet eine Übereinstimmung am Anfang der Zeichenfolge. Eine Ordnungssuche hingegen findet in beiden Fällen keine Übereinstimmung.

using System;

public class Example8
{
   public static void Main()
   {
      // Search for "oe" and "œu" in "œufs" and "oeufs".
      string s1 = "œufs";
      string s2 = "oeufs";
      FindInString(s1, "oe", StringComparison.CurrentCulture);
      FindInString(s1, "oe", StringComparison.Ordinal);
      FindInString(s2, "œu", StringComparison.CurrentCulture);
      FindInString(s2, "œu", StringComparison.Ordinal);
      Console.WriteLine();
      
      string s3 = "co\u00ADoperative";
      FindInString(s3, "\u00AD", StringComparison.CurrentCulture);
      FindInString(s3, "\u00AD", StringComparison.Ordinal);
   }

   private static void FindInString(string s, string substring, StringComparison options)
   {
      int result = s.IndexOf(substring, options);
      if (result != -1)
         Console.WriteLine("'{0}' found in {1} at position {2}", 
                           substring, s, result);
      else
         Console.WriteLine("'{0}' not found in {1}", 
                           substring, s);                                                  
   }
}
// The example displays the following output:
//       'oe' found in œufs at position 0
//       'oe' not found in œufs
//       'œu' found in oeufs at position 0
//       'œu' not found in oeufs
//       
//       '­' found in co­operative at position 0
//       '­' found in co­operative at position 2
open System

let findInString (s: string) (substring: string) (options: StringComparison) =
    let result = s.IndexOf(substring, options)
    if result <> -1 then
        printfn $"'{substring}' found in {s} at position {result}"
    else
        printfn $"'{substring}' not found in {s}"

// Search for "oe" and "œu" in "œufs" and "oeufs".
let s1 = "œufs"
let s2 = "oeufs"
findInString s1 "oe" StringComparison.CurrentCulture
findInString s1 "oe" StringComparison.Ordinal
findInString s2 "œu" StringComparison.CurrentCulture
findInString s2 "œu" StringComparison.Ordinal
printfn ""

let s3 = "co\u00ADoperative"
findInString s3 "\u00AD" StringComparison.CurrentCulture
findInString s3 "\u00AD" StringComparison.Ordinal

// The example displays the following output:
//       'oe' found in œufs at position 0
//       'oe' not found in œufs
//       'œu' found in oeufs at position 0
//       'œu' not found in oeufs
//
//       '­' found in co­operative at position 0
//       '­' found in co­operative at position 2
Module Example5
    Public Sub Main()
        ' Search for "oe" and "œu" in "œufs" and "oeufs".
        Dim s1 As String = "œufs"
        Dim s2 As String = "oeufs"
        FindInString(s1, "oe", StringComparison.CurrentCulture)
        FindInString(s1, "oe", StringComparison.Ordinal)
        FindInString(s2, "œu", StringComparison.CurrentCulture)
        FindInString(s2, "œu", StringComparison.Ordinal)
        Console.WriteLine()

        Dim softHyphen As String = ChrW(&HAD)
        Dim s3 As String = "co" + softHyphen + "operative"
        FindInString(s3, softHyphen, StringComparison.CurrentCulture)
        FindInString(s3, softHyphen, StringComparison.Ordinal)
    End Sub

    Private Sub FindInString(s As String, substring As String,
                            options As StringComparison)
        Dim result As Integer = s.IndexOf(substring, options)
        If result <> -1 Then
            Console.WriteLine("'{0}' found in {1} at position {2}",
                           substring, s, result)
        Else
            Console.WriteLine("'{0}' not found in {1}",
                           substring, s)
        End If
    End Sub
End Module
' The example displays the following output:
'       'oe' found in œufs at position 0
'       'oe' not found in œufs
'       'œu' found in oeufs at position 0
'       'œu' not found in oeufs
'       
'       '­' found in co­operative at position 0
'       '­' found in co­operative at position 2

Suchen in Zeichenfolgen

Zeichenfolgensuchmethoden, z String.StartsWith . B. und String.IndexOf, können auch kulturabhängige oder ordinale Zeichenfolgenvergleiche durchführen, um zu bestimmen, ob ein Zeichen oder eine Teilzeichenfolge in einer angegebenen Zeichenfolge gefunden wird.

Die Suchmethoden in der String Klasse, die nach einem einzelnen Zeichen suchen, z. B. die IndexOf Methode, oder eine von mehreren Zeichen, z. B. die IndexOfAny Methode, führen alle eine Ordnungssuche aus. Zum Ausführen einer Kultursensiblen Suche nach einem Zeichen müssen Sie eine CompareInfo Methode wie CompareInfo.IndexOf(String, Char) oder CompareInfo.LastIndexOf(String, Char). Beachten Sie, dass die Ergebnisse der Suche nach einem Zeichen mit Ordinal- und Kultursensiblen Vergleichen sehr unterschiedlich sein können. Beispielsweise kann eine Suche nach einem vorkompilierten Unicode-Zeichen wie der Ligatur "Æ" (U+00C6) je nach Kultur jedes Vorkommen seiner Komponenten in der richtigen Reihenfolge entsprechen, z. B. "AE" (U+041U+0045). Das folgende Beispiel veranschaulicht den Unterschied zwischen den Methoden und CompareInfo.IndexOf(String, Char) den String.IndexOf(Char) Methoden bei der Suche nach einem einzelnen Zeichen. Die Ligatur "æ" (U+00E6) befindet sich in der Zeichenfolge "Luft" bei Verwendung der Konventionen der en-US-Kultur, aber nicht bei Verwendung der Konventionen der Da-DK-Kultur oder beim Durchführen eines Ordinalvergleichs.

using System;
using System.Globalization;

public class Example17
{
   public static void Main()
   {
      String[] cultureNames = { "da-DK", "en-US" };
      CompareInfo ci;
      String str = "aerial";
      Char ch = 'æ';  // U+00E6
      
      Console.Write("Ordinal comparison -- ");
      Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
                        str.IndexOf(ch));
      
      foreach (var cultureName in cultureNames) {
         ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo;
         Console.Write("{0} cultural comparison -- ", cultureName);
         Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
                           ci.IndexOf(str, ch));
      }
   }
}
// The example displays the following output:
//       Ordinal comparison -- Position of 'æ' in aerial: -1
//       da-DK cultural comparison -- Position of 'æ' in aerial: -1
//       en-US cultural comparison -- Position of 'æ' in aerial: 0
open System.Globalization

let cultureNames = [| "da-DK"; "en-US" |]
let str = "aerial"
let ch = 'æ'  // U+00E6

printf "Ordinal comparison -- "
printfn $"Position of '{ch}' in {str}: {str.IndexOf ch}"
                  
for cultureName in cultureNames do
    let ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo
    printf $"{cultureName} cultural comparison -- "
    printfn $"Position of '{ch}' in {str}: {ci.IndexOf(str, ch)}"
// The example displays the following output:
//       Ordinal comparison -- Position of 'æ' in aerial: -1
//       da-DK cultural comparison -- Position of 'æ' in aerial: -1
//       en-US cultural comparison -- Position of 'æ' in aerial: 0
Imports System.Globalization

Module Example19
    Public Sub Main()
        Dim cultureNames() As String = {"da-DK", "en-US"}
        Dim ci As CompareInfo
        Dim str As String = "aerial"
        Dim ch As Char = "æ"c  ' U+00E6

        Console.Write("Ordinal comparison -- ")
        Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
                        str.IndexOf(ch))

        For Each cultureName In cultureNames
            ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo
            Console.Write("{0} cultural comparison -- ", cultureName)
            Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
                           ci.IndexOf(str, ch))
        Next
    End Sub
End Module
' The example displays the following output:
'       Ordinal comparison -- Position of 'æ' in aerial: -1
'       da-DK cultural comparison -- Position of 'æ' in aerial: -1
'       en-US cultural comparison -- Position of 'æ' in aerial: 0

Andererseits führen Klassenmethoden, String die anstelle eines Zeichens nach einer Zeichenfolge suchen, eine kultursensible Suche aus, wenn Suchoptionen nicht explizit durch einen Parameter vom Typ StringComparisonangegeben werden. Die einzige Ausnahme ist Contains, die eine Ordnungssuche durchführt.

Testen auf Gleichheit

Verwenden Sie die String.Compare Methode, um die Beziehung zweier Zeichenfolgen in der Sortierreihenfolge zu bestimmen. In der Regel handelt es sich hierbei um einen kulturempfindlichen Vorgang. Rufen Sie dagegen die String.Equals Methode auf, um die Gleichheit zu testen. Da der Test auf Gleichheit in der Regel die Benutzereingabe mit einer bekannten Zeichenfolge vergleicht, z. B. einen gültigen Benutzernamen, ein Kennwort oder einen Dateisystempfad, handelt es sich in der Regel um einen Ordinalvorgang.

Warnung

Es ist möglich, die Gleichheit durch Aufrufen der String.Compare Methode zu testen und zu bestimmen, ob der Rückgabewert null ist. Diese Vorgehensweise wird jedoch nicht empfohlen. Um festzustellen, ob zwei Zeichenfolgen gleich sind, sollten Sie eine der Überladungen der String.Equals Methode aufrufen. Die bevorzugte Überladung ist entweder die Instanzmethode Equals(String, StringComparison) oder die statische Equals(String, String, StringComparison) Methode, da beide Methoden einen System.StringComparison Parameter enthalten, der explizit den Typ des Vergleichs angibt.

Im folgenden Beispiel wird die Gefahr veranschaulicht, dass stattdessen ein kultursensitiver Vergleich für die Gleichheit durchgeführt wird, wenn stattdessen ein Ordinal verwendet werden sollte. In diesem Fall besteht die Absicht des Codes darin, den Dateisystemzugriff von URLs zu verbieten, die mit "FILE://" oder "file://" beginnen, indem ein Vergleich zwischen Groß- und Kleinschreibung des Anfangs einer URL mit der Zeichenfolge "FILE://" ausgeführt wird. Wenn jedoch ein kultursensibler Vergleich mit der türkischen Kultur (Türkei) auf einer URL durchgeführt wird, die mit "file://" beginnt, schlägt der Vergleich für Gleichheit fehl, da die türkische Großbuchstabenentsprechung des Kleinbuchstabens "i" "İ" anstelle von "I" ist. Daher ist der Dateisystemzugriff versehentlich zulässig. Wenn dagegen ein Ordinalvergleich durchgeführt wird, ist der Vergleich der Gleichheit erfolgreich, und der Dateisystemzugriff wird verweigert.

using System;
using System.Globalization;
using System.Threading;

public class Example4
{
   public static void Main()
   {
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR");      

      string filePath = "file://c:/notes.txt";
      
      Console.WriteLine("Culture-sensitive test for equality:");
      if (! TestForEquality(filePath, StringComparison.CurrentCultureIgnoreCase))
         Console.WriteLine("Access to {0} is allowed.", filePath);
      else
         Console.WriteLine("Access to {0} is not allowed.", filePath);
      
      Console.WriteLine("\nOrdinal test for equality:");
      if (! TestForEquality(filePath, StringComparison.OrdinalIgnoreCase))
         Console.WriteLine("Access to {0} is allowed.", filePath);
      else
         Console.WriteLine("Access to {0} is not allowed.", filePath);
   }

   private static bool TestForEquality(string str, StringComparison cmp)
   {
      int position = str.IndexOf("://");
      if (position < 0) return false;

      string substring = str.Substring(0, position);  
      return substring.Equals("FILE", cmp);
   }
}
// The example displays the following output:
//       Culture-sensitive test for equality:
//       Access to file://c:/notes.txt is allowed.
//       
//       Ordinal test for equality:
//       Access to file://c:/notes.txt is not allowed.
open System
open System.Globalization
open System.Threading

let testForEquality (str: string) (cmp: StringComparison) =
    let position = str.IndexOf "://"
    if position < 0 then false
    else
        let substring = str.Substring(0, position)
        substring.Equals("FILE", cmp)

Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "tr-TR"

let filePath = "file://c:/notes.txt"

printfn "Culture-sensitive test for equality:"
if not (testForEquality filePath StringComparison.CurrentCultureIgnoreCase) then
    printfn $"Access to {filePath} is allowed."
else
    printfn $"Access to {filePath} is not allowed."

printfn "\nOrdinal test for equality:"
if not (testForEquality filePath StringComparison.OrdinalIgnoreCase) then
    printfn $"Access to {filePath} is allowed."
else
    printfn $"Access to {filePath} is not allowed."

// The example displays the following output:
//       Culture-sensitive test for equality:
//       Access to file://c:/notes.txt is allowed.
//
//       Ordinal test for equality:
//       Access to file://c:/notes.txt is not allowed.
Imports System.Globalization
Imports System.Threading

Module Example7
    Public Sub Main()
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR")

        Dim filePath As String = "file://c:/notes.txt"

        Console.WriteLine("Culture-sensitive test for equality:")
        If Not TestForEquality(filePath, StringComparison.CurrentCultureIgnoreCase) Then
            Console.WriteLine("Access to {0} is allowed.", filePath)
        Else
            Console.WriteLine("Access to {0} is not allowed.", filePath)
        End If
        Console.WriteLine()

        Console.WriteLine("Ordinal test for equality:")
        If Not TestForEquality(filePath, StringComparison.OrdinalIgnoreCase) Then
            Console.WriteLine("Access to {0} is allowed.", filePath)
        Else
            Console.WriteLine("Access to {0} is not allowed.", filePath)
        End If
    End Sub

    Private Function TestForEquality(str As String, cmp As StringComparison) As Boolean
        Dim position As Integer = str.IndexOf("://")
        If position < 0 Then Return False

        Dim substring As String = str.Substring(0, position)
        Return substring.Equals("FILE", cmp)
    End Function
End Module
' The example displays the following output:
'       Culture-sensitive test for equality:
'       Access to file://c:/notes.txt is allowed.
'       
'       Ordinal test for equality:
'       Access to file://c:/notes.txt is not allowed.

Normalisierung

Einige Unicode-Zeichen weisen mehrere Darstellungen auf. Beispielsweise kann jeder der folgenden Codepunkte den Buchstaben "ắ" darstellen:

  • U+1EAF
  • U+0103 U+0301
  • U+0061 U+0306 U+0301

Mehrere Darstellungen für ein einzelnes Zeichen erschweren das Suchen, Sortieren, Abgleichen und andere Zeichenfolgenvorgänge.

Der Unicode-Standard definiert einen Prozess namens Normalisierung, der eine binäre Darstellung eines Unicode-Zeichens für eine der entsprechenden binären Darstellungen zurückgibt. Normalisierung kann mehrere Algorithmen verwenden, die als Normalisierungsformulare bezeichnet werden, die verschiedenen Regeln entsprechen. .NET unterstützt Unicode-Normalisierungsformulare C, D, KC und KD. Wenn Zeichenfolgen auf die gleiche Normalisierungsform normalisiert wurden, können sie mithilfe eines Ordinalvergleichs verglichen werden.

Ein Ordinalvergleich ist ein binärer Vergleich des Unicode-Skalarwerts entsprechender Char Objekte in jeder Zeichenfolge. Die String Klasse enthält eine Reihe von Methoden, die einen Ordinalvergleich durchführen können, einschließlich der folgenden:

Sie können ermitteln, ob eine Zeichenfolge in Normalisierungsform C normalisiert wird, indem Sie die String.IsNormalized() Methode aufrufen, oder Sie können die String.IsNormalized(NormalizationForm) Methode aufrufen, um zu bestimmen, ob eine Zeichenfolge auf ein angegebenes Normalisierungsformular normalisiert ist. Sie können die String.Normalize() Methode auch aufrufen, um eine Zeichenfolge in Normalisierungsform C zu konvertieren, oder Sie können die String.Normalize(NormalizationForm) Methode aufrufen, um eine Zeichenfolge in ein angegebenes Normalisierungsformular zu konvertieren. Schrittweise Informationen zum Normalisieren und Vergleichen von Zeichenfolgen finden Sie unter den Normalize() Und Normalize(NormalizationForm) Methoden.

Das folgende einfache Beispiel veranschaulicht die Zeichenfolgennormalisierung. Es definiert den Buchstaben "ố" auf drei verschiedene Arten in drei verschiedenen Zeichenfolgen und verwendet einen Ordinalvergleich für die Gleichheit, um zu bestimmen, dass sich jede Zeichenfolge von den anderen beiden Zeichenfolgen unterscheidet. Anschließend konvertiert sie jede Zeichenfolge in die unterstützten Normalisierungsformulare und führt erneut einen Ordinalvergleich jeder Zeichenfolge in einer angegebenen Normalisierungsform durch. In jedem Fall zeigt der zweite Test auf Gleichheit, dass die Zeichenfolgen gleich sind.

using System;
using System.Globalization;
using System.IO;
using System.Text;

public class Example13
{
   private static StreamWriter sw;
   
   public static void Main()
   {
      sw = new StreamWriter(@".\TestNorm1.txt");

      // Define three versions of the same word. 
      string s1 = "sống";        // create word with U+1ED1
      string s2 = "s\u00F4\u0301ng";
      string s3 = "so\u0302\u0301ng";

      TestForEquality(s1, s2, s3);      
      sw.WriteLine();

      // Normalize and compare strings using each normalization form.
      foreach (string formName in Enum.GetNames(typeof(NormalizationForm)))
      {
         sw.WriteLine("Normalization {0}:\n", formName); 
         NormalizationForm nf = (NormalizationForm) Enum.Parse(typeof(NormalizationForm), formName);
         string[] sn = NormalizeStrings(nf, s1, s2, s3);
         TestForEquality(sn);           
         sw.WriteLine("\n");                                        
      }
      
      sw.Close();   
   }

   private static void TestForEquality(params string[] words)
   {
      for (int ctr = 0; ctr <= words.Length - 2; ctr++)
         for (int ctr2 = ctr + 1; ctr2 <= words.Length - 1; ctr2++) 
            sw.WriteLine("{0} ({1}) = {2} ({3}): {4}", 
                         words[ctr], ShowBytes(words[ctr]),
                         words[ctr2], ShowBytes(words[ctr2]),
                         words[ctr].Equals(words[ctr2], StringComparison.Ordinal));
   }

   private static string ShowBytes(string str)
   {
      string result = null;
      foreach (var ch in str)
         result += $"{(ushort)ch:X4} ";
      return result.Trim();            
   } 
   
   private static string[] NormalizeStrings(NormalizationForm nf, params string[] words)
   {
      for (int ctr = 0; ctr < words.Length; ctr++)
         if (! words[ctr].IsNormalized(nf))
            words[ctr] = words[ctr].Normalize(nf); 
      return words;   
   }
}
// The example displays the following output:
//       sống (0073 1ED1 006E 0067) = sống (0073 00F4 0301 006E 0067): False
//       sống (0073 1ED1 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
//       sống (0073 00F4 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
//       
//       Normalization FormC:
//       
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       
//       
//       Normalization FormD:
//       
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       
//       
//       Normalization FormKC:
//       
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       
//       
//       Normalization FormKD:
//       
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
open System
open System.IO
open System.Text

do
    use sw = new StreamWriter(@".\TestNorm1.txt")

    let showBytes (str: string) =
        let mutable result = ""
        for ch in str do
            result <- result + $"{uint16 ch:X4} "
        result.Trim()
    
    let testForEquality (words: string[]) =
        for ctr = 0 to words.Length - 2 do
            for ctr2 = ctr + 1 to words.Length - 1 do
                sw.WriteLine("{0} ({1}) = {2} ({3}): {4}",
                            words[ctr], showBytes(words[ctr]),
                            words[ctr2], showBytes(words[ctr2]),
                            words[ctr].Equals(words[ctr2], StringComparison.Ordinal))

    let normalizeStrings nf (words: string[]) =
        for i = 0 to words.Length - 1 do
            if not (words[i].IsNormalized nf) then
                words[i] <- words[i].Normalize nf
        words

    // Define three versions of the same word.
    let s1 = "sống"        // create word with U+1ED1
    let s2 = "s\u00F4\u0301ng"
    let s3 = "so\u0302\u0301ng"

    testForEquality [| s1; s2; s3 |]
    sw.WriteLine()

    // Normalize and compare strings using each normalization form.
    for formName in Enum.GetNames typeof<NormalizationForm> do
        sw.WriteLine("Normalization {0}:\n", formName)
        let nf = Enum.Parse(typeof<NormalizationForm>, formName) :?> NormalizationForm
        let sn = normalizeStrings nf [| s1; s2; s3|]
        testForEquality sn
        sw.WriteLine "\n"

// The example displays the following output:
//       sống (0073 1ED1 006E 0067) = sống (0073 00F4 0301 006E 0067): False
//       sống (0073 1ED1 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
//       sống (0073 00F4 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
//
//       Normalization FormC:
//
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//
//
//       Normalization FormD:
//
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//
//
//       Normalization FormKC:
//
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//
//
//       Normalization FormKD:
//
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
Imports System.Globalization
Imports System.IO
Imports System.Text

Module Example16
    Private sw As StreamWriter

    Public Sub Main()
        sw = New StreamWriter(".\TestNorm1.txt")

        ' Define three versions of the same word. 
        Dim s1 As String = "sống"        ' create word with U+1ED1
        Dim s2 As String = "s" + ChrW(&HF4) + ChrW(&H301) + "ng"
        Dim s3 As String = "so" + ChrW(&H302) + ChrW(&H301) + "ng"

        TestForEquality(s1, s2, s3)
        sw.WriteLine()

        ' Normalize and compare strings using each normalization form.
        For Each formName In [Enum].GetNames(GetType(NormalizationForm))
            sw.WriteLine("Normalization {0}:", formName)
            Dim nf As NormalizationForm = CType([Enum].Parse(GetType(NormalizationForm), formName),
                                             NormalizationForm)
            Dim sn() As String = NormalizeStrings(nf, s1, s2, s3)
            TestForEquality(sn)
            sw.WriteLine(vbCrLf)
        Next

        sw.Close()
    End Sub

    Private Sub TestForEquality(ParamArray words As String())
        For ctr As Integer = 0 To words.Length - 2
            For ctr2 As Integer = ctr + 1 To words.Length - 1
                sw.WriteLine("{0} ({1}) = {2} ({3}): {4}",
                         words(ctr), ShowBytes(words(ctr)),
                         words(ctr2), ShowBytes(words(ctr2)),
                         words(ctr).Equals(words(ctr2), StringComparison.Ordinal))
            Next
        Next
    End Sub

    Private Function ShowBytes(str As String) As String
        Dim result As String = Nothing
        For Each ch In str
            result += String.Format("{0} ", Convert.ToUInt16(ch).ToString("X4"))
        Next
        Return result.Trim()
    End Function

    Private Function NormalizeStrings(nf As NormalizationForm, ParamArray words() As String) As String()
        For ctr As Integer = 0 To words.Length - 1
            If Not words(ctr).IsNormalized(nf) Then
                words(ctr) = words(ctr).Normalize(nf)
            End If
        Next
        Return words
    End Function
End Module
' The example displays the following output:
'       sống (0073 1ED1 006E 0067) = sống (0073 00F4 0301 006E 0067): False
'       sống (0073 1ED1 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
'       sống (0073 00F4 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
'       
'       Normalization FormC:
'       
'       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'       
'       
'       Normalization FormD:
'       
'       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
'       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
'       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
'       
'       
'       Normalization FormKC:
'       
'       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'       sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'       
'       
'       Normalization FormKD:
'       
'       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
'       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
'       sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True

Weitere Informationen zu Normalisierungs- und Normalisierungsformularen finden Sie im System.Text.NormalizationFormUnicode-Standard-Anhang Nr. 15: Unicode Normalisierungsformulare und die häufig gestellten Fragen zur Normalisierung auf der website unicode.org.

Zeichenfolgenvorgänge nach Kategorie

Die String Klasse bietet Member zum Vergleichen von Zeichenfolgen, Testen von Zeichenfolgen auf Gleichheit, Suchen von Zeichen oder Teilzeichenfolgen in einer Zeichenfolge, Ändern einer Zeichenfolge, Extrahieren von Teilzeichenfolgen aus einer Zeichenfolge, Kombinieren von Zeichenfolgen, Formatierungswerte, Kopieren einer Zeichenfolge und Normalisieren einer Zeichenfolge.

Vergleichen von Zeichenfolgen

Sie können Zeichenfolgen vergleichen, um ihre relative Position in der Sortierreihenfolge zu bestimmen, indem Sie die folgenden String Methoden verwenden:

  • Compare gibt eine ganze Zahl zurück, die die Beziehung einer Zeichenfolge zu einer zweiten Zeichenfolge in der Sortierreihenfolge angibt.

  • CompareOrdinal gibt eine ganze Zahl zurück, die die Beziehung einer Zeichenfolge zu einer zweiten Zeichenfolge basierend auf einem Vergleich ihrer Codepunkte angibt.

  • CompareTo gibt eine ganze Zahl zurück, die die Beziehung der aktuellen Zeichenfolgeninstanz zu einer zweiten Zeichenfolge in der Sortierreihenfolge angibt. Die CompareTo(String) Methode stellt die IComparable Klassen und IComparable<T> Implementierungen bereit String .

Testen von Zeichenfolgen auf Gleichheit

Sie rufen die Equals Methode auf, um zu bestimmen, ob zwei Zeichenfolgen gleich sind. Mit der Instanz Equals(String, String, StringComparison) und den statischen Equals(String, StringComparison) Überladungen können Sie angeben, ob der Vergleich kultursensitiv oder ordinal ist und ob die Groß-/Kleinschreibung berücksichtigt oder ignoriert wird. Die meisten Tests auf Gleichheit sind Ordnungszahlen, und Vergleiche für Gleichheit, die den Zugriff auf eine Systemressource (z. B. ein Dateisystemobjekt) bestimmen, sollten immer Ordnungszahl sein.

Suchen von Zeichen in einer Zeichenfolge

Die String Klasse enthält zwei Arten von Suchmethoden:

  • Methoden, die einen Boolean Wert zurückgeben, um anzugeben, ob eine bestimmte Teilzeichenfolge in einer Zeichenfolgeninstanz vorhanden ist. Dazu gehören die ContainsMethoden und EndsWithStartsWith Methoden.

  • Methoden, die die Anfangsposition einer Teilzeichenfolge in einer Zeichenfolgeninstanz angeben. Dazu gehören die IndexOfMethoden , , IndexOfAny, LastIndexOfund LastIndexOfAny die Methoden.

Warnung

Wenn Sie eine Zeichenfolge für ein bestimmtes Muster anstelle einer bestimmten Teilzeichenfolge durchsuchen möchten, sollten Sie reguläre Ausdrücke verwenden. Weitere Informationen finden Sie unter reguläre .NET-Ausdrücke.

Ändern einer Zeichenfolge

Die String Klasse enthält die folgenden Methoden, die angezeigt werden, um den Wert einer Zeichenfolge zu ändern:

  • Insert fügt eine Zeichenfolge in die aktuelle String Instanz ein.

  • PadLeft Fügt ein oder mehrere Vorkommen eines angegebenen Zeichens am Anfang einer Zeichenfolge ein.

  • PadRight Fügt ein oder mehrere Vorkommen eines angegebenen Zeichens am Ende einer Zeichenfolge ein.

  • Remove löscht eine Teilzeichenfolge aus der aktuellen String Instanz.

  • Replace ersetzt eine Teilzeichenfolge durch eine andere Teilzeichenfolge in der aktuellen String Instanz.

  • ToLower und ToLowerInvariant konvertieren Sie alle Zeichen in einer Zeichenfolge in Kleinbuchstaben.

  • ToUpper und ToUpperInvariant konvertieren Sie alle Zeichen in einer Zeichenfolge in Großbuchstaben.

  • Trim Entfernt alle Vorkommen eines Zeichens vom Anfang und Ende einer Zeichenfolge.

  • TrimEnd Entfernt alle Vorkommen eines Zeichens vom Ende einer Zeichenfolge.

  • TrimStart Entfernt alle Vorkommen eines Zeichens vom Anfang einer Zeichenfolge.

Wichtig

Alle Zeichenfolgenänderungsmethoden geben ein neues String Objekt zurück. Sie ändern nicht den Wert der aktuellen Instanz.

Extrahieren von Teilzeichenfolgen aus einer Zeichenfolge

Die String.Split Methode trennt eine einzelne Zeichenfolge in mehrere Zeichenfolgen. Überladungen der Methode ermöglichen es Ihnen, mehrere Trennzeichen anzugeben, die Anzahl der Teilzeichenfolgen zu begrenzen, die die Methode extrahiert, leerer Leerraum aus Teilzeichenfolgen zu kürzen und anzugeben, ob leere Zeichenfolgen (die auftreten, wenn Trennzeichen nebeneinander liegen) in die zurückgegebenen Zeichenfolgen eingeschlossen werden.

Kombinieren von Zeichenfolgen

Die folgenden String Methoden können für die Zeichenfolgenverkettung verwendet werden:

  • Concat kombiniert eine oder mehrere Teilzeichenfolgen in einer einzelnen Zeichenfolge.
  • Join Verkettet eine oder mehrere Teilzeichenfolgen in ein einzelnes Element und fügt ein Trennzeichen zwischen den einzelnen Teilzeichenfolgen hinzu.

Formatieren von Werten

Die String.Format Methode verwendet das Zusammengesetztformatierungsfeature, um einen oder mehrere Platzhalter in einer Zeichenfolge durch die Zeichenfolgendarstellung eines Objekts oder Werts zu ersetzen. Die Format Methode wird häufig verwendet, um Folgendes auszuführen:

  • So betten Sie die Zeichenfolgendarstellung eines numerischen Werts in eine Zeichenfolge ein.
  • So betten Sie die Zeichenfolgendarstellung eines Datums- und Uhrzeitwerts in eine Zeichenfolge ein.
  • So betten Sie die Zeichenfolgendarstellung eines Enumerationswerts in eine Zeichenfolge ein.
  • So betten Sie die Zeichenfolgendarstellung eines Objekts ein, das die IFormattable Schnittstelle in einer Zeichenfolge unterstützt.
  • Um eine Teilzeichenfolge in einem Feld innerhalb einer größeren Zeichenfolge rechtsbündig oder links zu rechtfertigen.

Ausführliche Informationen zu Formatierungsvorgängen und Beispielen finden Sie in der Format Überladungszusammenfassung.

Kopieren einer Zeichenfolge

Sie können die folgenden String Methoden aufrufen, um eine Kopie einer Zeichenfolge zu erstellen:

  • Clone gibt einen Verweis auf ein vorhandenes String Objekt zurück.
  • Copy erstellt eine Kopie einer vorhandenen Zeichenfolge.
  • CopyTo kopiert einen Teil einer Zeichenfolge in ein Zeichenarray.

Normalisieren einer Zeichenfolge

In Unicode kann ein einzelnes Zeichen mehrere Codepunkte aufweisen. Die Normalisierung konvertiert diese entsprechenden Zeichen in dieselbe binäre Darstellung. Die String.Normalize Methode führt die Normalisierung aus, und die String.IsNormalized Methode bestimmt, ob eine Zeichenfolge normalisiert ist.

Weitere Informationen und ein Beispiel finden Sie weiter oben in diesem Artikel im Abschnitt "Normalisierung ".