System.String-klass

Kommentar

Den här artikeln innehåller ytterligare kommentarer till referensdokumentationen för det här API:et.

En sträng är en sekventiell samling tecken som används för att representera text. Ett String objekt är en sekventiell samling System.Char objekt som representerar en sträng. Ett System.Char objekt motsvarar en UTF-16-kodenhet. Objektets String värde är innehållet i den sekventiella samlingen av System.Char objekt och det värdet är oföränderligt (det vill: det är skrivskyddat). Mer information om oföränderlighet för strängar finns i avsnittet Oföränderlighet och Klassen StringBuilder . Den maximala storleken på ett String objekt i minnet är 2 GB eller cirka 1 miljard tecken.

Mer information om Unicode, UTF-16, kodenheter, kodpunkter och typer finns CharRunei Introduktion till teckenkodning i .NET.

Instansiera ett strängobjekt

Du kan instansiera ett String objekt på följande sätt:

  • Genom att tilldela en strängliteral till en String variabel. Det här är den vanligaste metoden för att skapa en sträng. I följande exempel används tilldelning för att skapa flera strängar. Observera att i C# och F#, eftersom omvänt snedstreck (\) är ett escape-tecken, måste literala omvänt snedstreck i en sträng vara undantagna eller så måste hela strängen vara @-citerad.

    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
    
  • Genom att anropa en String klasskonstruktor. I följande exempel instansierar du strängar genom att anropa flera klasskonstruktorer. Observera att vissa konstruktorer innehåller pekare till teckenmatriser eller signerade bytematriser som parametrar. Visual Basic stöder inte anrop till dessa konstruktorer. Detaljerad information om String konstruktorer finns i konstruktorsammanfattningen String .

    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
    
  • Genom att använda strängsammanfogningsoperatorn (+ i C# och F# och & eller + i Visual Basic) för att skapa en enda sträng från valfri kombination av String instanser och strängliteraler. I följande exempel visas hur strängsammanfogningsoperatorn används.

    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.
    
  • Genom att hämta en egenskap eller anropa en metod som returnerar en sträng. I följande exempel används metoderna för String klassen för att extrahera en delsträng från en större sträng.

    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
    
  • Genom att anropa en formateringsmetod för att konvertera ett värde eller objekt till dess strängrepresentation. I följande exempel används funktionen sammansatt formatering för att bädda in strängrepresentationen av två objekt i en sträng.

    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-objekt och Unicode-tecken

Varje tecken i en sträng definieras av ett Unicode-skalärvärde, även kallat unicode-kodpunkt eller ordningstalsvärdet (numeriskt) för Unicode-tecknet. Varje kodpunkt kodas med hjälp av UTF-16-kodning, och det numeriska värdet för varje element i kodningen representeras av ett Char objekt.

Kommentar

Observera att eftersom en String instans består av en sekventiell samling UTF-16-kodenheter är det möjligt att skapa ett String objekt som inte är en välformulerad Unicode-sträng. Till exempel är det möjligt att skapa en sträng med ett lågsurrogat utan motsvarande högsurrogat. Även om vissa metoder, till exempel metoder för kodning och avkodning av objekt i System.Text namnområdet, kan utföra kontroller för att säkerställa att strängarna är välformulerade, String ser klassmedlemmar inte till att en sträng är välformulerad.

Ett enskilt Char objekt representerar vanligtvis en enda kodpunkt, dvs. det numeriska värdet för Char är lika med kodpunkten. Kodpunkten för tecknet "a" är till exempel U+0061. En kodpunkt kan dock kräva mer än ett kodat element (mer än ett Char objekt). Unicode-standarden definierar två typer av tecken som motsvarar flera Char objekt: graphemes och Unicode-tilläggskodpunkter som motsvarar tecken i unicode-tilläggsplan.

  • Ett grapheme representeras av ett bastecken följt av ett eller flera kombinationstecken. Till exempel representeras tecknet ä av ett Char objekt vars kodpunkt är U+0061 följt av ett Char objekt vars kodpunkt är U+0308. Det här tecknet kan också definieras av ett enskilt Char objekt som har kodpunkten U+00E4. Som följande exempel visar, indikerar en kulturkänslig jämförelse för likhet att dessa två representationer är lika, även om en ordinarie jämförelse med ordningstal inte gör det möjligt. Men om de två strängarna normaliseras indikerar en ordningsjämförelse också att de är lika. (Mer information om hur du normaliserar strängar finns i Normaliseringsavsnitt .)

    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
    
  • En Unicode-tilläggskodpunkt (ett surrogatpar) representeras av ett Char objekt vars kodpunkt är en hög surrogat följt av ett Char objekt vars kodpunkt är en låg surrogat. Kodenheterna för höga surrogater sträcker sig från U+D800 till U+DBFF. Kodenheterna för låg surrogat varierar från U+DC00 till U+DFFF. Surrogatpar används för att representera tecken i de 16 Unicode-tilläggsplan. Exemplet nedan skapar ett surrogattecken och skickar det till Char.IsSurrogatePair(Char, Char)-metoden för att avgöra om det utgör ett surrogatpar.

    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: {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
    

Unicode-standarden

Tecken i en sträng representeras av UTF-16-kodade kodenheter, som motsvarar Char värden.

Varje tecken i en sträng har en associerad Unicode-teckenkategori, som representeras i .NET av UnicodeCategory uppräkningen. Kategorin för ett tecken eller ett surrogatpar kan fastställas genom att anropa CharUnicodeInfo.GetUnicodeCategory metoden.

.NET har en egen tabell med tecken och motsvarande kategorier, vilket säkerställer att en specifik version av en .NET-implementering som körs på olika plattformar returnerar identisk teckenkategoriinformation. På alla .NET-versioner och på alla OS-plattformar tillhandahålls information om teckenkategori i Unicode-teckendatabasen.

I följande tabell visas .NET-versioner och de versioner av Unicode Standard som deras teckenkategorier baseras på.

.NET-version Version av Unicode Standard
.NET Framework 1.1 Unicode Standard, version 4.0.0
.NET Framework 2.0 Unicode Standard, version 5.0.0
.NET Framework 3.5 Unicode Standard, version 5.0.0
.NET Framework 4 Unicode Standard, version 5.0.0
.NET Framework 4.5 Unicode Standard, version 6.3.0
.NET Framework 4.5.1 Unicode Standard, version 6.3.0
.NET Framework 4.5.2 Unicode Standard, version 6.3.0
.NET framework 4.6 Unicode Standard, version 6.3.0
.NET Framework 4.6.1 Unicode Standard, version 6.3.0
.NET Framework 4.6.2 och senare versioner Unicode Standard, version 8.0.0
.NET Core 2.1 Unicode Standard, version 8.0.0
.NET Core 3.1 Unicode Standard, version 11.0.0
.NET 5 Unicode Standard, version 13.0.0

Dessutom stöder .NET strängjämförelse och sortering baserat på Unicode-standarden. Från och med .NET Framework 4.5 som körs på Windows 8 och senare versioner av Windows-operativsystemet delegerar körningen strängjämförelser och sorteringsåtgärder till operativsystemet. I .NET Core och .NET 5+ tillhandahålls strängjämförelse- och sorteringsinformation av internationella komponenter för Unicode-bibliotek (förutom i Windows-versioner före Maj 2019-uppdatering för Windows 10). I följande tabell visas versionerna av .NET och versionerna av Unicode Standard som teckenjämförelse och sortering baseras på.

.NET-version Version av Unicode Standard
.NET Framework 4.5 och senare i Windows 7 Unicode Standard, version 5.0.0
.NET Framework 4.5 och senare i Windows 8 och senare Windows-operativsystem Unicode Standard, version 6.3.0
.NET Core och .NET 5+ Beror på vilken version av Unicode Standard som stöds av det underliggande operativsystemet.

Inbäddade nulltecken

I .NET kan ett String objekt innehålla inbäddade nulltecken, som räknas som en del av strängens längd. Men på vissa språk, till exempel C och C++, anger ett null-tecken slutet på en sträng. den anses inte vara en del av strängen och räknas inte som en del av strängens längd. Det innebär att följande vanliga antaganden som C- och C++-programmerare eller bibliotek som skrivits i C eller C++ kan göra om strängar inte nödvändigtvis är giltiga när de tillämpas på String objekt:

  • Värdet som returneras av strlen funktionerna eller wcslen är inte nödvändigtvis lika med String.Length.

  • Strängen strcpy_s som skapas av funktionerna eller wcscpy_s är inte nödvändigtvis identisk med strängen som kopieras.

Du bör se till att inbyggd C- och C++-kod som instansierar String objekt och kod som skickas String via plattformsanrop inte förutsätter att ett inbäddat null-tecken markerar slutet på strängen.

Inbäddade null-tecken i en sträng behandlas också på olika sätt när en sträng sorteras (eller jämförs) och när en sträng genomsöks. Null-tecken ignoreras när du utför kulturkänsliga jämförelser mellan två strängar, inklusive jämförelser med den invarianta kulturen. De anses endast för ordinale jämförelser eller skiftlägesokänsliga ordinale jämförelser. Å andra sidan beaktas alltid inbäddade null-tecken när du söker i en sträng med metoder som Contains, StartsWithoch IndexOf.

Strängar och index

Ett index är positionen för ett Char objekt (inte ett Unicode-tecken) i en String. Ett index är ett nollbaserat, icke-negativt tal som börjar från den första positionen i en sträng, som är indexposition noll. Ett antal sökmetoder, till exempel IndexOf och LastIndexOf, returnerar indexet för ett tecken eller en delsträng i stränginstansen.

Med Chars[Int32] egenskapen kan du komma åt enskilda Char objekt efter deras indexposition i strängen. Eftersom egenskapen Chars[Int32] är standardegenskapen (i Visual Basic) eller indexeraren (i C# och F#), kan du komma åt de enskilda Char objekten i en sträng med hjälp av kod som följande. Den här koden letar efter blanksteg eller skiljetecken i en sträng för att avgöra hur många ord strängen innehåller.

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
   {s1}
 has {nWords} words.
 """);                                                                     
// 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.

String Eftersom klassen implementerar IEnumerable gränssnittet kan du också iterera genom objekten Char i en sträng med hjälp av en foreach konstruktion, som i följande exempel visas.

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
   {s1}
 has {nWords} words.
 """);
// 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.

Efterföljande indexvärden kanske inte motsvarar på varandra följande Unicode-tecken, eftersom ett Unicode-tecken kan kodas som mer än ett Char objekt. I synnerhet kan en sträng innehålla textenheter med flera tecken som bildas av ett bastecken följt av ett eller flera kombinationstecken eller surrogatpar. Om du vill arbeta med Unicode-tecken i stället för Char objekt använder du System.Globalization.StringInfo klasserna och TextElementEnumerator eller String.EnumerateRunes metoden och structen Rune . I följande exempel visas skillnaden mellan kod som fungerar med Char objekt och kod som fungerar med Unicode-tecken. Den jämför antalet tecken eller textelement i varje ord i en mening. Strängen innehåller två sekvenser av ett bastecken följt av ett kombinerande tecken.

// 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

Det här exemplet fungerar med textelement med hjälp StringInfo.GetTextElementEnumerator av metoden och TextElementEnumerator klassen för att räkna upp alla textelement i en sträng. Du kan också hämta en matris som innehåller startindexet för varje textelement genom att anropa StringInfo.ParseCombiningCharacters metoden.

Mer information om hur du arbetar med textenheter i stället för enskilda Char värden finns i Introduktion till teckenkodning i .NET.

Null-strängar och tomma strängar

En sträng som har deklarerats men inte har tilldelats något värde är null. Om du försöker anropa metoder på den strängen kastas ett NullReferenceException. En null-sträng skiljer sig från en tom sträng, som är en sträng vars värde är "" eller String.Empty. I vissa fall kastas ett undantag när man skickar antingen en null-sträng eller en tom sträng som argument i ett metodanrop. Om du till exempel skickar en null-sträng till Int32.Parse metoden genererar en ArgumentNullException, och om du skickar en tom sträng utlöss en FormatException. I andra fall kan ett metodargument vara antingen en null-sträng eller en tom sträng. Om du till exempel tillhandahåller en IFormattable implementering för en klass vill du likställa både en null-sträng och en tom sträng med den allmänna formatspecificeraren ("G").

Klassen String innehåller följande två bekvämlighetsmetoder som gör att du kan testa om en sträng är null eller tom:

  • IsNullOrEmpty, som anger om en sträng är antingen null eller är lika med String.Empty. Den här metoden eliminerar behovet av att använda kod, till exempel följande:

    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, som anger om en sträng är null, är lika med String.Emptyeller endast består av blankstegstecken. Den här metoden eliminerar behovet av att använda kod, till exempel följande:

    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
    

I följande exempel används IsNullOrEmpty metoden i implementeringen IFormattable.ToString av en anpassad Temperature klass. Metoden stöder formatsträngarna "G", "C", "F" och "K". Om en tom formatsträng eller en formatsträng vars värde null skickas till metoden ändras dess värde till formatsträngen "G".

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

Oföränderlighet och StringBuilder-klassen

Ett String objekt kallas oföränderligt (skrivskyddat), eftersom dess värde inte kan ändras när det har skapats. Metoder som verkar ändra ett String objekt returnerar faktiskt ett nytt String objekt som innehåller ändringen.

Eftersom strängar är oföränderliga kan strängmanipuleringsrutiner som utför upprepade tillägg eller borttagningar till vad som verkar vara en enda sträng kräva en betydande prestandastraff. Följande kod använder till exempel en slumptalsgenerator för att skapa en sträng med 1 000 tecken i intervallet 0x0001 till 0x052F. Även om koden verkar använda strängsammanfogning för att lägga till ett nytt tecken i den befintliga strängen med namnet str, skapar den faktiskt ett nytt String objekt för varje sammanfogningsåtgärd.

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

Du kan använda StringBuilder klassen istället för String klassen för åtgärder som gör flera ändringar i värdet för en sträng. Till skillnad från instanser av String klassen StringBuilder är objekt föränderliga. När du sammanfogar, lägger till eller tar bort delsträngar från en sträng utförs åtgärderna på en enda sträng. När du har ändrat värdet för ett StringBuilder objekt kan du anropa dess StringBuilder.ToString metod för att konvertera det till en sträng. I följande exempel ersätts det String som användes i föregående exempel för att sammanfoga 1 000 slumpmässiga tecken i intervallet för att 0x0001 till 0x052F med ett StringBuilder objekt.

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

Ordningsoperationer kontra kulturkänsliga operationer

Medlemmar i String klassen utför antingen ordnings- eller kulturkänsliga (språkliga) åtgärder på ett String objekt. En ordinal operation tillämpas på det numeriska värdet för varje Char-objekt. En kulturkänslig funktion verkar på värdet av String-objektet och tar hänsyn till kulturspecifik kapitalisering, sortering, formatering och tolkning. Kulturkänsliga åtgärder körs i kontexten för en uttryckligen deklarerad kultur eller den implicita aktuella kulturen. De två typerna av åtgärder kan ge mycket olika resultat när de utförs på samma sträng.

.NET stöder också kulturokänsliga språksträngsåtgärder med hjälp av den invarianta kulturen (CultureInfo.InvariantCulture), som är löst baserad på kulturinställningarna för det engelska språket oberoende av region. Till skillnad från andra System.Globalization.CultureInfo inställningar är inställningarna för den invarianta kulturen garanterat konsekventa på en enda dator, från system till system och mellan versioner av .NET. Den invarianta kulturen kan ses som en slags svart låda som garanterar stabilitet i strängjämförelser och ordning i alla kulturer.

Viktigt!

Om ditt program fattar ett säkerhetsbeslut om en symbolisk identifierare, till exempel ett filnamn eller ett namngivet rör, eller om bevarade data, till exempel textbaserade data i en XML-fil, bör åtgärden använda en ordningstalsjämförelse i stället för en kulturkänslig jämförelse. Det beror på att en kulturkänslig jämförelse kan ge olika resultat beroende på vilken kultur som gäller, medan en ordningstalsjämförelse enbart beror på det binära värdet för de jämförna tecknen.

Viktigt!

De flesta metoder som utför strängoperationer inkluderar en överladdning som har en parameter av typen StringComparison, som gör att du kan ange om metoden utför en ordinal eller kulturkänslig operation. Generellt sett bör du anropa den här överbelastningen för att tydliggöra syftet med ditt metodanrop. Metodtips och vägledning för användning av ordningstal och kulturkänsliga åtgärder på strängar finns i Metodtips för att använda strängar.

Åtgärder för hölje, parsning och formatering, jämförelse och sortering samt testning för likhet kan vara antingen ordningstalskänsliga eller kulturkänsliga. I följande avsnitt beskrivs varje åtgärdskategori.

Tips

Du bör alltid anropa en metodöverbelastning som gör avsikten med ditt metodanrop klar. I stället för att anropa Compare(String, String) metoden för att utföra en kulturkänslig jämförelse av två strängar med hjälp av konventionerna i den aktuella kulturen bör du anropa Compare(String, String, StringComparison) metoden med värdet StringComparison.CurrentCulture för för comparisonType argumentet. Mer information finns i Metodtips för att använda strängar.

Du kan ladda ned sorteringsvikttabellerna, en uppsättning textfiler som innehåller information om de teckenvikter som används i sorterings- och jämförelseåtgärder, från följande länkar:

Hölje

Regler för versalisering bestämmer hur man ändrar versaliseringen av ett Unicode-tecken; till exempel från gemener till versaler. Ofta utförs en höljeåtgärd före en strängjämförelse. En sträng kan till exempel konverteras till versaler så att den kan jämföras med en annan versalsträng. Du kan konvertera tecknen i en sträng till gemener genom att anropa metoden ToLower eller ToLowerInvariant och du kan konvertera dem till versaler genom att anropa metoden ToUpper eller ToUpperInvariant. Dessutom kan du använda TextInfo.ToTitleCase metoden för att konvertera en sträng till rubrikfall.

Kommentar

.NET Core körs endast på Linux- och macOS-system: Sorteringsbeteendet för C- och Posix-kulturerna är alltid skiftlägeskänsligt eftersom dessa kulturer inte använder den förväntade Unicode-sorteringsordningen. Vi rekommenderar att du använder en annan kultur än C eller Posix för att utföra kulturkänsliga, skiftlägesokänsliga sorteringsåtgärder.

Höljeåtgärder kan baseras på reglerna för den aktuella kulturen, en angiven kultur eller den invarianta kulturen. Eftersom skiftlägesmappningar kan variera beroende på vilken kultur som används kan resultatet av skiftlägesåtgärder variera beroende på kulturen. De faktiska skillnaderna i hölje är av tre slag:

  • Skillnader i skiftlägesmappning av LATINSK VERSAL BOKSTAV I (U+0049), LATINSK LITEN BOKSTAV I (U+0069), LATINSK VERSAL BOKSTAV I MED PUNKT OVAN (U+0130) och LATINSK LITEN BOKSTAV I UTAN PUNKT (U+0131). I tr-TR (turkiska (Turkiet)) och az-Latn-AZ (Azerbajdzjan, Latin) kulturerna, samt i de neutrala kulturerna tr, az och az-Latn, är den gemena motsvarigheten till LATINSK VERSAL BOKSTAV I, LATINSK LITEN BOKSTAV DOTLESS I, och den versala motsvarigheten till LATINSK LITEN BOKSTAV I är LATINSK VERSAL BOKSTAV I MED PUNKT OVAN. I alla andra kulturer, inklusive den invarianta kulturen, är LATIN SMÅ BOKSTAV I och LATINSK VERSAL BOKSTAV I motsvarande gemener och versaler.

    I följande exempel visas hur en strängjämförelse som är utformad för att förhindra filsystemåtkomst kan misslyckas om den förlitar sig på en kulturkänslig höljejämförelse. (Höljekonventionerna i den invarianta kulturen borde ha använts.)

    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: {CultureInfo.CurrentCulture.DisplayName}");
             Console.WriteLine(resource);
             Console.WriteLine($"Access allowed: {! 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
    
  • Skillnader i fallmappningar mellan den invarianta kulturen och alla andra kulturer. I dessa fall, när en teckenändring görs till versaler eller gemener enligt reglerna för höljesättning i den invarianta kulturen, returneras samma tecken. För alla andra kulturer returneras ett annat tecken. Några av de berörda tecknen visas i följande tabell.

    Tecken Om det ändras till Returer
    MIKRONTECKEN (U+00B5) Versaler GREKISK VERSAL BOKSTAV MU (U+-39C)
    LATINSK STOR BOKSTAV I MED PUNKT OVANFÖR (U+0130) Gemener LATINSK LITEN BOKSTAV I (U+0069)
    LATINSK LITEN BOKSTAV I UTAN PUNKT (U+0131) Versaler LATINSK VERSAL BOKSTAV I (U+0049)
    LATINSK LITEN BOKSTAV LÅNG S (U+017F) Versaler LATINSK VERSAL BOKSTAV S (U+0053)
    LATINSK STOR BOKSTAV D OCH LITEN BOKSTAV Z MED CARON (U+01C5) Gemener LATINSK LITEN BOKSTAV DZ MED CARON (U+01C6)
    KOMBINERA GREKISKA YPOGEGRAMMENI (U+0345) Versaler GREKISKA VERSALER IOTA (U+0399)
  • Skillnader i fallmappningar av tvåbokstavspar med blandade skiftlägen i ASCII-teckenintervallet. I de flesta kulturer är ett tvåbokstavspar med blandat skiftläge lika med motsvarande två versaler eller två gemener. Detta gäller inte för följande tvåbokstavspar i följande kulturer, eftersom de i varje fall jämförs med en digraf:

    • "lJ" och "nJ" i kulturen hr-HR (kroatiska) i Kroatien.
    • "cH" i kulturerna cs-CZ (Tjeckien) och sk-SK (Slovakien).
    • "aA" i da-DK-kulturen (Danmark).
    • "cS", "dZ", "dZS", "nY", "sZ", "tY" och "zS" i hu-HU-kulturen (Ungern)).
    • "cH" och "lL" i kulturen es-ES_tradnl (spanska (Spanien, traditionell sortering)).
    • "cH", "gI", "kH", "nG", "nH", "pH", "qU', "tH" och "tR" i den vietnamesiska (vi-VN, Vietnam) kulturen.

    Det är dock ovanligt att stöta på en situation där en kulturkänslig jämförelse av dessa par skapar problem, eftersom dessa par är ovanliga i fasta strängar eller identifierare.

I följande exempel visas några av skillnaderna i höljeregler mellan kulturer när strängar konverteras till versaler.

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

Parsning och formatering

Formatering och parsning är omvända åtgärder. Formateringsregler bestämmer hur du konverterar ett värde, till exempel ett datum och en tid eller ett tal, till dess strängrepresentation, medan parsningsregler bestämmer hur du konverterar en strängrepresentation till ett värde, till exempel ett datum och en tid. Både formaterings- och parsningsregler är beroende av kulturella konventioner. I följande exempel visas den tvetydighet som kan uppstå när du tolkar en kulturspecifik datumsträng. Utan att känna till konventionerna i den kultur som användes för att producera en datumsträng är det inte möjligt att veta om 03/01/2011, 3/1/2011 och 01/03/2011 representerar 3 januari 2011 eller 1 mars 2011.

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

På samma sätt, som i följande exempel, kan en enskild sträng producera olika datum beroende på vilken kultur vars konventioner används i parsningsåtgärden.

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

Strängjämförelse och sortering

Konventioner för att jämföra och sortera strängar varierar från kultur till kultur. Sorteringsordningen kan till exempel baseras på fonetik eller på den visuella representationen av tecken. I östasiatiska språk sorteras tecken efter streckantal och radikaler i ideografier. Sortering beror också på vilken ordning språk och kulturer använder för alfabetet. Det danska språket har till exempel ett "Æ"-tecken som det sorterar efter "Z" i alfabetet. Dessutom kan jämförelser vara skiftlägeskänsliga eller skiftlägesokänsliga, och höljereglerna kan skilja sig åt beroende på kultur. I en ordningsjämförelse används däremot Unicode-kodpunkterna för enskilda tecken i en sträng vid jämförelse och sortering av strängar.

Sorteringsregler avgör den alfabetiska ordningen för Unicode-tecken och hur två strängar jämförs med varandra. Metoden jämför till exempel String.Compare(String, String, StringComparison) två strängar baserat på parametern StringComparison . Om parametervärdet är StringComparison.CurrentCultureutför metoden en språklig jämförelse som använder den aktuella kulturens konventioner. Om parametervärdet är StringComparison.Ordinalutför metoden en ordningstalsjämförelse. Som följande exempel visar, om den aktuella kulturen är amerikansk engelska, räknar det första anropet till metoden (med kulturkänslig jämförelse) "a" som mindre än "A", men det andra anropet till samma metod (med ordinal jämförelse) betraktar "a" som större än "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 stöder sorteringsregler för ord, sträng och ordning:

  • En ordsortering utför en kulturkänslig jämförelse av strängar där vissa icke-numeriska Unicode-tecken kan ha särskilda vikter tilldelade till sig. Till exempel kan bindestrecket (-) ha tilldelats en mycket liten vikt så att "coop" och "co-op" visas bredvid varandra i en sorterad lista. En lista över de String metoder som jämför två strängar med hjälp av ordsorteringsregler finns i avsnittet Strängåtgärder efter kategori .

  • En strängsortering utför också en kulturkänslig jämförelse. Det liknar en ordsortering, förutom att det inte finns några specialfall, och alla icke-numeriska symboler kommer före alla alfanumeriska Unicode-tecken. Två strängar kan jämföras med strängsorteringsregler genom att anropa de CompareInfo.Compare metodöverlagringar som har en options parameter som har värdet CompareOptions.StringSort. Observera att det här är den enda metoden som .NET tillhandahåller för att jämföra två strängar med hjälp av strängsorteringsregler.

  • En ordningssortering jämför strängar baserat på det numeriska värdet för varje Char objekt i strängen. En ordinal jämförelse är automatiskt skiftlägeskänslig eftersom gemener och versaler av ett tecken har olika kodpunkter. Men om ärendet inte är viktigt kan du ange en ordningstalsjämförelse som ignorerar skiftläge. Detta motsvarar att konvertera strängen till versaler med hjälp av den invarianta kulturen och sedan utföra en ordningsjämförelse på resultatet. En lista över de String metoder som jämför två strängar med ordningstalssorteringsregler finns i avsnittet Strängåtgärder efter kategori .

En kulturkänslig jämförelse är en jämförelse som uttryckligen eller implicit använder ett CultureInfo objekt, inklusive den invarianta kultur som anges av CultureInfo.InvariantCulture egenskapen. Den implicita kulturen är den aktuella kulturen, som anges av Thread.CurrentCulture egenskaperna och CultureInfo.CurrentCulture . Det finns en betydande variation i sorteringsordningen för alfabetiska tecken (det vill: tecken som Char.IsLetter metoden returnerar true) mellan kulturer. Du kan ange en kulturkänslig jämförelse som använder konventionerna för en viss kultur genom att ange ett CultureInfo objekt till en strängjämförelsemetod, Compare(String, String, CultureInfo, CompareOptions)till exempel . Du kan ange en kulturkänslig jämförelse som använder konventionerna i den aktuella kulturen genom att ange StringComparison.CurrentCulture, StringComparison.CurrentCultureIgnoreCase eller någon annan medlem i CompareOptions-uppräkningen än CompareOptions.Ordinal eller CompareOptions.OrdinalIgnoreCase till en lämplig överbelastning av metoden Compare. En kulturkänslig jämförelse är i allmänhet lämplig för sortering, medan en ordningstalsjämförelse inte är det. En ordningsjämförelse är vanligtvis lämplig för att avgöra om två strängar är lika (dvs. för att fastställa identitet) medan en kulturkänslig jämförelse inte är det.

I följande exempel illustreras skillnaden mellan kulturkänslig och ordinal jämförelse. Exemplet utvärderar tre strängar, "Apple", "Æble" och "AEble", med hjälp av ordningstalsjämförelse och konventionerna för da-DK- och en-US-kulturerna (som var och en är standardkulturen vid den Compare tidpunkt då metoden anropas). Eftersom det danska språket behandlar tecknet "Æ" som en enskild bokstav och sorterar det efter "Z" i alfabetet, är strängen "Æble" större än "Apple". "Æble" anses dock inte motsvara "AEble", så "Æble" är också större än "AEble". Den anglosaxiska kulturen inkluderar inte bokstaven "Æ", men behandlar den som likvärdig med "AE", vilket förklarar varför "Æble" är mindre än "Apple" men lika med "AEble". En ordningsjämförelse anser å andra sidan att "Apple" är mindre än "Æble" och "Æble" är större än "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: {CultureInfo.CurrentCulture.Name}");
      Console.WriteLine($"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}");
      Console.WriteLine($"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n");
      
      // Set the current culture to English in the U.S.
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine($"Current culture: {CultureInfo.CurrentCulture.Name}");
      Console.WriteLine($"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}");
      Console.WriteLine($"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n");
      
      // Perform an ordinal comparison.
      Console.WriteLine("Ordinal comparison");
      Console.WriteLine($"Comparison of {str1} with {str2}: {String.Compare(str1, str2, StringComparison.Ordinal)}");
      Console.WriteLine($"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
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

Använd följande allmänna riktlinjer för att välja en lämplig sorterings- eller strängjämförelsemetod:

  • Om du vill att strängarna ska ordnas baserat på användarens kultur bör du beställa dem baserat på den aktuella kulturens konventioner. Om användarens kultur ändras ändras även ordningen på sorterade strängar. Ett synonymprogram bör till exempel alltid sortera ord baserat på användarens kultur.

  • Om du vill att strängarna ska ordnas baserat på konventionerna i en specifik kultur bör du beställa dem genom att ange ett CultureInfo objekt som representerar den kulturen till en jämförelsemetod. I ett program som är utformat för att lära eleverna ett visst språk vill du till exempel att strängar ska beställas baserat på konventionerna i en av de kulturer som talar det språket.

  • Om du vill att ordningen på strängar ska förbli oförändrad mellan kulturer bör du beställa dem baserat på konventionerna i den invarianta kulturen eller använda en ordningstalsjämförelse. Du skulle till exempel använda en ordinalsökning för att organisera namnen på filer, processer, mutexar eller namngivna rör.

  • För en jämförelse som omfattar ett säkerhetsbeslut (till exempel om ett användarnamn är giltigt) bör du alltid utföra ett ordningstalstest för likhet genom att anropa en överbelastning av Equals metoden.

Kommentar

De kulturkänsliga sorterings- och höljereglerna som används i strängjämförelse beror på versionen av .NET. På .NET Core beror strängjämförelse på vilken version av Unicode Standard som stöds av det underliggande operativsystemet. I .NET Framework 4.5 och senare versioner som körs på Windows 8 eller senare överensstämmer sortering, hölje, normalisering och Unicode-teckeninformation med Unicode 6.0-standarden. På andra Windows-operativsystem överensstämmer de med Unicode 5.0-standarden.

Mer information om sorteringsregler för ord, sträng och ordning finns i avsnittet System.Globalization.CompareOptions . Ytterligare rekommendationer om när du ska använda varje regel finns i Metodtips för att använda strängar.

Vanligtvis anropar du inte strängjämförelsemetoder som Compare direkt för att fastställa sorteringsordningen för strängar. I stället anropas jämförelsemetoder genom sorteringsmetoder som Array.Sort eller List<T>.Sort. I följande exempel utförs fyra olika sorteringsåtgärder (ordsortering med den aktuella kulturen, ordsortering med hjälp av den invarianta kulturen, ordningssortering och strängsortering med hjälp av den invarianta kulturen) utan att uttryckligen anropa en strängjämförelsemetod, även om de anger vilken typ av jämförelse som ska användas. Observera att varje typ av sortering ger en unik sortering av strängar i matrisen.

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

Tips

Internt använder .NET sorteringsnycklar för att stödja kulturellt känsliga strängjämförelser. Varje tecken i en sträng ges flera kategorier av sorteringsvikter, inklusive alfabetiska, skiftläges- och diakritiska vikter. En sorteringsnyckel, som representeras av SortKey klassen, tillhandahåller en lagringsplats med dessa vikter för en viss sträng. Om din app utför ett stort antal söknings- eller sorteringsåtgärder på samma uppsättning strängar kan du förbättra dess prestanda genom att generera och lagra sorteringsnycklar för alla strängar som används. När en sorterings- eller jämförelseåtgärd krävs använder du sorteringsnycklarna i stället för strängarna. Mer information finns i SortKey klassen .

Om du inte anger en strängjämförelsekonvention, sorteringsmetoder som Array.Sort(Array) utför en kulturkänslig, skiftlägeskänslig sortering på strängar. I följande exempel visas hur ändring av den aktuella kulturen påverkar ordningen på sorterade strängar i en matris. Den skapar en matris med tre strängar. Först anger den System.Threading.Thread.CurrentThread.CurrentCulture egenskapen till en-US och anropar Array.Sort(Array) metoden. Den resulterande sorteringsordningen baseras på sorteringskonventioner för den engelska (USA) kulturen. Nästa steg är att exemplet sätter egenskapen System.Threading.Thread.CurrentThread.CurrentCulture till da-DK och anropar Array.Sort-metoden igen. Observera hur den resulterande sorteringsordningen skiljer sig från resultatet en-US eftersom den använder sorteringskonventionerna för danska (Danmark).

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($"[{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

Varning

Om det primära syftet med att jämföra strängar är att avgöra om de är lika bör du anropa String.Equals metoden. Normalt bör du använda Equals för att utföra en ordningstalsjämförelse. Metoden String.Compare är främst avsedd att sortera strängar.

Strängsökningsmetoder, till exempel String.StartsWith och String.IndexOf, kan också utföra kulturkänsliga eller ordningsberoende strängjämförelser. I följande exempel visas skillnaderna mellan ordningstal och kulturkänsliga jämförelser med hjälp av IndexOf metoden. En kulturkänslig sökning där den nuvarande kulturen är engelska (USA) anser att substring "oe" matchar ligaturen "œ". Eftersom ett mjukt bindestreck (U+00AD) är ett tecken med noll bredd behandlar sökningen det mjuka bindestrecket som likvärdigt String.Empty med och hittar en matchning i början av strängen. En sekventiell sökning hittar å andra sidan ingen matchning, vare sig i något av fallen.

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($"'{substring}' found in {s} at position {result}");
      else
         Console.WriteLine($"'{substring}' not found in {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

Sök i strängar

Strängsökningsmetoder, till exempel String.StartsWith och String.IndexOf, kan också utföra kulturkänsliga eller ordningskänsliga strängjämförelser för att avgöra om ett tecken eller en delsträng finns i en angiven sträng.

Sökmetoderna String i klassen som söker efter ett enskilt tecken, till IndexOf exempel metoden eller ett av en uppsättning tecken, till exempel IndexOfAny metoden, utför alla en ordningstalssökning. Om du vill utföra en kulturkänslig sökning efter ett tecken måste du anropa en CompareInfo metod som CompareInfo.IndexOf(String, Char) eller CompareInfo.LastIndexOf(String, Char). Observera att resultatet av att söka efter ett tecken med hjälp av ordningstal och kulturkänslig jämförelse kan skilja sig mycket åt. Till exempel kan en sökning efter ett förkomponerat Unicode-tecken, till exempel ligaturen "Æ" (U+00C6) matcha alla förekomster av dess komponenter i rätt sekvens, till exempel "AE" (U+041U+0045), beroende på kulturen. I följande exempel visas skillnaden mellan String.IndexOf(Char) metoderna och CompareInfo.IndexOf(String, Char) när du söker efter ett enskilt tecken. Ligaturen "æ" (U+00E6) finns i strängen "aerial" när du använder konventionerna i en-US-kulturen, men inte när du använder konventionerna i da-DK-kulturen eller när du gör en jämförelse baserad på ordningsföljd.

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 '{ch}' in {str}: {str.IndexOf(ch)}");
      
      foreach (var cultureName in cultureNames) {
         ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo;
         Console.Write("{0} cultural comparison -- ", cultureName);
         Console.WriteLine($"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
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

Å andra sidan String utför klassmetoder som söker efter en sträng i stället för ett tecken en kulturkänslig sökning om sökalternativen inte uttryckligen anges av en parameter av typen StringComparison. Det enda undantaget är Contains, som utför en ordningsbaserad sökning.

Test för likhet

String.Compare Använd metoden för att fastställa relationen mellan två strängar i sorteringsordningen. Detta är vanligtvis en kulturkänslig åtgärd. Anropa däremot String.Equals metoden för att testa för likhet. Eftersom likhetstestet vanligtvis jämför användarindata med en känd sträng, till exempel ett giltigt användarnamn, ett lösenord eller en filsystemsökväg, är det vanligtvis en ordinal jämförelse.

Varning

Det går att testa likheten genom att anropa String.Compare metoden och avgöra om returvärdet är noll. Den här metoden rekommenderas dock inte. För att avgöra om två strängar är lika bör du anropa en av String.Equals metodens överlagringar. Den föredragna överbelastningen att anropa är antingen instansmetoden Equals(String, StringComparison) eller den statiska Equals(String, String, StringComparison)-metoden, eftersom de båda innehåller en System.StringComparison-parameter som specifikt anger jämförelsetypen.

I följande exempel visas risken med att göra en kulturkänslig jämförelse för likhet när en ordningsbaserad jämförelse borde användas istället. I det här fallet är avsikten med koden att förbjuda filsystemåtkomst från URL:er som börjar med "FILE://" eller "file://" genom att utföra en skiftlägesokänslig jämförelse av början av en URL med strängen "FILE://". Men om en kulturkänslig jämförelse utförs med hjälp av den turkiska (Turkiet) kulturen på en URL som börjar med "file://", misslyckas jämförelsen för likhet eftersom den turkiska versalmotsvarigheten till gemenen "i" är "İ" i stället för "I". Därför tillåts filsystemåtkomst oavsiktligt. Å andra sidan, om en ordningsjämförelse utförs, lyckas jämförelsen för likhet och filsystemåtkomst nekas.

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 {filePath} is allowed.");
      else
         Console.WriteLine($"Access to {filePath} is not allowed.");
      
      Console.WriteLine("\nOrdinal test for equality:");
      if (! TestForEquality(filePath, StringComparison.OrdinalIgnoreCase))
         Console.WriteLine($"Access to {filePath} is allowed.");
      else
         Console.WriteLine($"Access to {filePath} is not allowed.");
   }

   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.

Normalisering

Vissa Unicode-tecken har flera representationer. Till exempel kan någon av följande kodpunkter representera bokstaven "ắ":

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

Flera representationer för ett enskilt tecken komplicerar sökning, sortering, matchning och andra strängåtgärder.

Unicode-standarden definierar en process som kallas normalisering som returnerar en binär representation av ett Unicode-tecken för någon av dess motsvarande binära representationer. Normalisering kan använda flera algoritmer, så kallade normaliseringsformulär, som följer olika regler. .NET stöder Unicode-normaliseringsformulären C, D, KC och KD. När strängar har normaliserats till samma normaliseringsformulär kan de jämföras med hjälp av ordningstalsjämförelse.

En ordningsjämförelse är en binär jämförelse av Unicode-skalärvärdet för motsvarande Char objekt i varje sträng. Klassen String innehåller ett antal metoder som kan utföra en ordningsjämförelse, inklusive följande:

Du kan avgöra om en sträng normaliseras till normaliseringsformulär C genom att anropa String.IsNormalized() metoden, eller så kan du anropa String.IsNormalized(NormalizationForm) metoden för att avgöra om en sträng normaliseras till ett angivet normaliseringsformulär. Du kan också anropa String.Normalize() metoden för att konvertera en sträng till normaliseringsformulär C, eller så kan du anropa String.Normalize(NormalizationForm) metoden för att konvertera en sträng till ett angivet normaliseringsformulär. Stegvis information om hur du normaliserar och jämför strängar finns i Normalize() metoderna och Normalize(NormalizationForm) .

Följande enkla exempel illustrerar strängnormalisering. Den definierar bokstaven "ố" på tre olika sätt i tre olika strängar och använder en ordningsjämförelse för likhet för att fastställa att varje sträng skiljer sig från de andra två strängarna. Sedan konverteras varje sträng till de normaliseringsformulär som stöds och utför återigen en ordningsjämförelse av varje sträng i ett angivet normaliseringsformulär. I varje fall visar det andra testet för likhet att strängarna är lika.

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

Mer information om normaliserings- och normaliseringsformulär finns i System.Text.NormalizationForm, samt Unicode Standard Annex #15: Unicode Normalization Forms och Vanliga frågor och svar om normalisering på unicode.org webbplats.

Strängåtgärder efter kategori

Klassen String innehåller medlemmar för att jämföra strängar, testa strängar för likhet, hitta tecken eller delsträngar i en sträng, ändra en sträng, extrahera delsträngar från en sträng, kombinera strängar, formatera värden, kopiera en sträng och normalisera en sträng.

Jämföra strängar

Du kan jämföra strängar för att fastställa deras relativa position i sorteringsordningen med hjälp av följande String metoder:

  • Compare returnerar ett heltal som anger relationen mellan en sträng och en andra sträng i sorteringsordningen.

  • CompareOrdinal returnerar ett heltal som anger relationen mellan en sträng och en andra sträng baserat på en jämförelse av deras kodpunkter.

  • CompareTo returnerar ett heltal som anger relationen mellan den aktuella stränginstansen och en andra sträng i sorteringsordningen. Metoden CompareTo(String) tillhandahåller IComparable implementeringarna och IComparable<T> för String klassen.

Testa strängar för likhet

Du anropar Equals metoden för att avgöra om två strängar är lika med. Med instansen Equals(String, String, StringComparison) och de statiska Equals(String, StringComparison) överlagringarna kan du ange om jämförelsen är kulturkänslig eller ordningskänslig och om ärendet betraktas eller ignoreras. De flesta tester för likhet är ordningstal och jämförelser för likhet som avgör åtkomsten till en systemresurs (till exempel ett filsystemobjekt) bör alltid vara ordningstal.

Hitta tecken i en sträng

Klassen String innehåller två typer av sökmetoder:

Varning

Om du vill söka efter ett visst mönster i stället för en viss delsträng bör du använda reguljära uttryck. Mer information finns i Reguljära .NET-uttryck.

Ändra en sträng

Klassen String innehåller följande metoder som verkar ändra värdet för en sträng:

  • Insert infogar en sträng i den aktuella String instansen.

  • PadLeft infogar en eller flera förekomster av ett angivet tecken i början av en sträng.

  • PadRight infogar en eller flera förekomster av ett angivet tecken i slutet av en sträng.

  • Remove tar bort en delsträng från den aktuella String instansen.

  • Replace ersätter en delsträng med en annan delsträng i den aktuella String instansen.

  • ToLower och ToLowerInvariant konverterar alla tecken i en sträng till gemener.

  • ToUpper och ToUpperInvariant konverterar alla tecken i en sträng till versaler.

  • Trim tar bort alla förekomster av ett tecken från början och slutet av en sträng.

  • TrimEnd tar bort alla förekomster av ett tecken från slutet av en sträng.

  • TrimStart tar bort alla förekomster av ett tecken från början av en sträng.

Viktigt!

Alla strängmodifieringsmetoder returnerar ett nytt String objekt. De ändrar inte värdet för den aktuella instansen.

Extrahera delsträngar från en sträng

Metoden String.Split separerar en enskild sträng i flera strängar. Med överlagringar av metoden kan du ange flera avgränsare, begränsa antalet delsträngar som metoden extraherar, trimma tomt utrymme från delsträngar och ange om tomma strängar (som inträffar när avgränsare är intill) ingår i de returnerade strängarna.

Kombinera strängar

Följande String metoder kan användas för strängsammanfogning:

  • Concat kombinerar en eller flera delsträngar i en enda sträng.
  • Join sammanfogar en eller flera delsträngar till ett enda element och lägger till en avgränsare mellan varje delsträng.

Formatera värden

Metoden String.Format använder funktionen sammansatt formatering för att ersätta en eller flera platshållare i en sträng med strängrepresentationen av något objekt eller värde. Metoden Format används ofta för att göra följande:

  • Bädda in strängrepresentationen av ett numeriskt värde i en sträng.
  • Bädda in strängrepresentationen av ett datum- och tidsvärde i en sträng.
  • Bädda in strängrepresentationen av ett uppräkningsvärde i en sträng.
  • Bädda in strängrepresentationen av ett objekt som stöder IFormattable gränssnittet i en sträng.
  • För att högerjustera eller vänsterjustera en delsträng i ett fält i en större sträng.

Detaljerad information om formateringsåtgärder och exempel finns i översikten över Format överbelastning.

Kopiera en sträng

Du kan anropa följande String metoder för att göra en kopia av en sträng:

  • Clone returnerar en referens till ett befintligt String objekt.
  • CopyTo kopierar en del av en sträng till en teckenmatris.

Normalisera en sträng

I Unicode kan ett enskilt tecken ha flera kodpunkter. Normaliseringen konverterar dessa motsvarande tecken till samma binära representation. Metoden String.Normalize utför normaliseringen och String.IsNormalized metoden avgör om en sträng normaliseras.

Mer information och ett exempel finns i avsnittet Normalisering tidigare i den här artikeln.