System.String classe
Este artigo fornece observações complementares à documentação de referência para essa API.
Uma cadeia de caracteres é uma coleção sequencial de caracteres usada para representar texto. Um String objeto é uma coleção sequencial de objetos que representam uma cadeia de caracteres, um System.Char objeto corresponde a uma unidade de System.Char código UTF-16. O valor do String objeto é o conteúdo da coleção sequencial de System.Char objetos, e esse valor é imutável (ou seja, é somente leitura). Para obter mais informações sobre a imutabilidade de cadeias de caracteres, consulte a seção Imutabilidade e a classe StringBuilder. O tamanho máximo de um String objeto na memória é de 2 GB, ou cerca de 1 bilhão de caracteres.
Para obter mais informações sobre Unicode, UTF-16, unidades de código, pontos de código e os tipos e Rune eChar, consulte Introdução à codificação de caracteres no .NET.
Instanciar um objeto String
Você pode instanciar um String objeto das seguintes maneiras:
Atribuindo um literal de cadeia de caracteres a uma String variável. Esse é o método mais comumente usado para criar uma cadeia de caracteres. O exemplo a seguir usa atribuição para criar várias cadeias de caracteres. Observe que em C# e F#, como a barra invertida (\) é um caractere de escape, barras invertidas literais em uma cadeia de caracteres devem ser escapadas ou a cadeia inteira deve ser @-quoted.
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
Chamando um construtor de String classe. O exemplo a seguir instancia cadeias de caracteres chamando vários construtores de classe. Observe que alguns dos construtores incluem ponteiros para matrizes de caracteres ou matrizes de bytes assinadas como parâmetros. Visual Basic não oferece suporte a chamadas para esses construtores. Para obter informações detalhadas sobre String construtores, consulte o resumo do String construtor.
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
Usando o operador de concatenação de cadeia de caracteres (+ em C# e F# e & ou + no Visual Basic) para criar uma única cadeia de caracteres a partir de qualquer combinação de instâncias e literais de cadeia de String caracteres. O exemplo a seguir ilustra o uso do operador de concatenação de cadeia de caracteres.
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.
Recuperando uma propriedade ou chamando um método que retorna uma cadeia de caracteres. O exemplo a seguir usa os String métodos da classe para extrair uma subcadeia de caracteres de uma cadeia de caracteres maior.
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
Chamando um método de formatação para converter um valor ou objeto em sua representação de cadeia de caracteres. O exemplo a seguir usa o recurso de formatação composta para incorporar a representação de cadeia de caracteres de dois objetos em uma cadeia de caracteres.
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.
Objetos Char e caracteres Unicode
Cada caractere em uma cadeia de caracteres é definido por um valor escalar Unicode, também chamado de ponto de código Unicode ou o valor ordinal (numérico) do caractere Unicode. Cada ponto de código é codificado usando a codificação UTF-16 e o valor numérico de cada elemento da codificação é representado por um Char objeto.
Observação
Observe que, como uma instância consiste em uma coleção sequencial de unidades de código UTF-16, é possível criar um String objeto que não seja uma String cadeia de caracteres Unicode bem formada. Por exemplo, é possível criar uma cadeia de caracteres que tenha um substituto baixo sem um substituto alto correspondente. Embora alguns métodos, como os métodos de codificação e decodificação de objetos no System.Text namespace, possam executar verificações para garantir que as cadeias de caracteres sejam bem formadas, String os membros da classe não garantem que uma cadeia de caracteres esteja bem formada.
Um único objeto geralmente representa um único Char ponto de código, ou seja, o valor numérico do Char é igual ao ponto de código. Por exemplo, o ponto de código para o caractere "a" é U+0061. No entanto, um ponto de código pode exigir mais de um elemento codificado (mais de um Char objeto). O padrão Unicode define dois tipos de caracteres que correspondem a vários Char objetos: grafemas e pontos de código suplementar Unicode que correspondem a caracteres nos planos suplementares Unicode.
Um grafema é representado por um caractere base seguido por um ou mais caracteres combinados. Por exemplo, o caractere ä é representado por um objeto cujo ponto de código é U+0061 seguido por um CharChar objeto cujo ponto de código é U+0308. Esse caractere também pode ser definido por um único Char objeto que tem um ponto de código de U+00E4. Como mostra o exemplo a seguir, uma comparação sensível à cultura para igualdade indica que essas duas representações são iguais, embora uma comparação ordinal comum não. No entanto, se as duas cadeias de caracteres forem normalizadas, uma comparação ordinal também indicará que elas são iguais. (Para obter mais informações sobre como normalizar cadeias de caracteres, consulte o Seção de normalização .)
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
Um ponto de código suplementar Unicode (um par substituto) é representado por um objeto cujo ponto de código é um substituto alto seguido por um objeto cujo ponto de código é um CharChar substituto baixo. As unidades de código de substitutos altos variam de U+D800 a U+DBFF. As unidades de código de substitutos baixos variam de U+DC00 a U+DFFF. Pares substitutos são usados para representar caracteres nos 16 planos suplementares Unicode. O exemplo a seguir cria um caractere substituto e o passa para o método para determinar se ele é um par substituto Char.IsSurrogatePair(Char, Char) .
string surrogate = "\uD800\uDC03"; for (int ctr = 0; ctr < surrogate.Length; ctr++) Console.Write($"U+{(ushort)surrogate[ctr]:X2} "); Console.WriteLine(); Console.WriteLine(" Is Surrogate Pair: {0}", Char.IsSurrogatePair(surrogate[0], surrogate[1])); // The example displays the following output: // U+D800 U+DC03 // Is Surrogate Pair: True
open System let surrogate = "\uD800\uDC03" for i = 0 to surrogate.Length - 1 do printf $"U+{uint16 surrogate[i]:X2} " printfn $"\n Is Surrogate Pair: {Char.IsSurrogatePair(surrogate[0], surrogate[1])}" // The example displays the following output: // U+D800 U+DC03 // Is Surrogate Pair: True
Module Example20 Public Sub Main() Dim surrogate As String = ChrW(&HD800) + ChrW(&HDC03) For ctr As Integer = 0 To surrogate.Length - 1 Console.Write("U+{0:X2} ", Convert.ToUInt16(surrogate(ctr))) Next Console.WriteLine() Console.WriteLine(" Is Surrogate Pair: {0}", Char.IsSurrogatePair(surrogate(0), surrogate(1))) End Sub End Module ' The example displays the following output: ' U+D800 U+DC03 ' Is Surrogate Pair: True
O padrão Unicode
Os caracteres em uma cadeia de caracteres são representados por unidades de código codificadas UTF-16, que correspondem a Char valores.
Cada caractere em uma cadeia de caracteres tem uma categoria de caractere Unicode associada, que é representada no .NET pela UnicodeCategory enumeração. A categoria de um caractere ou de um par substituto pode ser determinada chamando o CharUnicodeInfo.GetUnicodeCategory método.
O .NET mantém sua própria tabela de caracteres e suas categorias correspondentes, o que garante que uma versão específica de uma implementação do .NET em execução em diferentes plataformas retorne informações de categoria de caracteres idênticos. Em todas as versões do .NET e em todas as plataformas do sistema operacional, as informações de categoria de caracteres são fornecidas pelo Banco de Dados de Caracteres Unicode.
A tabela a seguir lista as versões do .NET e as versões do Padrão Unicode nas quais suas categorias de caracteres são baseadas.
Versão do .NET | Versão do Padrão Unicode |
---|---|
.NET Framework 1.1 | O Padrão Unicode, versão 4.0.0 |
.NET Framework 2.0 | O Padrão Unicode, versão 5.0.0 |
.NET Framework 3.5 | O Padrão Unicode, versão 5.0.0 |
.NET Framework 4 | O Padrão Unicode, versão 5.0.0 |
.NET Framework 4.5 | O Padrão Unicode, versão 6.3.0 |
.NET Framework 4.5.1 | O Padrão Unicode, versão 6.3.0 |
.NET Framework 4.5.2 | O Padrão Unicode, versão 6.3.0 |
.NET Framework 4.6 | O Padrão Unicode, versão 6.3.0 |
.NET Framework 4.6.1 | O Padrão Unicode, versão 6.3.0 |
.NET Framework 4.6.2 e versões posteriores | O Padrão Unicode, versão 8.0.0 |
.NET Core 2.1 | O Padrão Unicode, versão 8.0.0 |
.NET Core 3.1 | O padrão Unicode, versão 11.0.0 |
.NET 5 | O padrão Unicode, versão 13.0.0 |
Além disso, o .NET oferece suporte à comparação e classificação de cadeia de caracteres com base no padrão Unicode. A partir do .NET Framework 4.5 em execução no Windows 8 e em versões posteriores do sistema operacional Windows, o tempo de execução delega operações de comparação e classificação de cadeia de caracteres ao sistema operacional. No .NET Core e no .NET 5+, as informações de comparação e classificação de cadeias de caracteres são fornecidas pelas bibliotecas International Components for Unicode (exceto em versões do Windows anteriores à Atualização de maio de 2019 do Windows 10). A tabela a seguir lista as versões do .NET e as versões do Unicode Standard nas quais a comparação e a classificação de caracteres são baseadas.
Versão do .NET | Versão do Padrão Unicode |
---|---|
.NET Framework 4.5 e posterior no Windows 7 | O Padrão Unicode, versão 5.0.0 |
.NET Framework 4.5 e posterior no Windows 8 e sistemas operacionais Windows posteriores | O Padrão Unicode, versão 6.3.0 |
.NET Core e .NET 5+ | Depende da versão do padrão Unicode compatível com o sistema operacional subjacente. |
Caracteres nulos incorporados
No .NET, um String objeto pode incluir caracteres nulos incorporados, que contam como parte do comprimento da cadeia de caracteres. No entanto, em algumas linguagens, como C e C++, um caractere nulo indica o final de uma cadeia de caracteres; não é considerado uma parte da cadeia de caracteres e não é contado como parte do comprimento da corda. Isso significa que as seguintes suposições comuns que programadores ou bibliotecas C e C++ escritas em C ou C++ podem fazer sobre cadeias de caracteres não são necessariamente válidas quando aplicadas a String objetos:
O valor retornado pelas
strlen
funções ouwcslen
não é necessariamente igual String.Lengtha .A cadeia de caracteres criada pelas
strcpy_s
funções ouwcscpy_s
não é necessariamente idêntica à cadeia de caracteres criada pelo String.Copy método.
Você deve garantir que o código C e C++ nativo que instancia objetos e o código que é passado String objetos através da plataforma invocar, não assuma que um caractere nulo incorporado marca o String final da cadeia de caracteres.
Os caracteres nulos incorporados em uma cadeia de caracteres também são tratados de forma diferente quando uma cadeia de caracteres é classificada (ou comparada) e quando uma cadeia de caracteres é pesquisada. Caracteres nulos são ignorados ao executar comparações sensíveis à cultura entre duas cadeias de caracteres, incluindo comparações usando a cultura invariante. Eles são considerados apenas para comparações ordinais ou ordinais que não diferenciam maiúsculas de minúsculas. Por outro lado, caracteres nulos incorporados são sempre considerados ao pesquisar uma cadeia de caracteres com métodos como Contains, StartsWithe IndexOf.
Cadeias de caracteres e índices
Um índice é a posição de um objeto (não um caractere Unicode) em um CharStringarquivo . Um índice é um número não negativo baseado em zero que começa a partir da primeira posição na cadeia de caracteres, que é a posição zero do índice. Vários métodos de pesquisa, como IndexOf e , retornam o índice de um caractere LastIndexOfou subcadeia de caracteres na ocorrência de cadeia de caracteres.
A Chars[] propriedade permite acessar objetos individuais Char por sua posição de índice na cadeia de caracteres. Como a propriedade é a Chars[] propriedade padrão (no Visual Basic) ou o indexador (em C# e F#), você pode acessar os objetos individuais Char em uma cadeia de caracteres usando código como o seguinte. Esse código procura espaço em branco ou caracteres de pontuação em uma cadeia de caracteres para determinar quantas palavras a cadeia de caracteres contém.
string s1 = "This string consists of a single short sentence.";
int nWords = 0;
s1 = s1.Trim();
for (int ctr = 0; ctr < s1.Length; ctr++) {
if (Char.IsPunctuation(s1[ctr]) | Char.IsWhiteSpace(s1[ctr]))
nWords++;
}
Console.WriteLine("The sentence\n {0}\nhas {1} words.",
s1, nWords);
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
let s1 = "This string consists of a single short sentence."
let mutable nWords = 0
for i = 0 to s1.Length - 1 do
if Char.IsPunctuation s1[i] || Char.IsWhiteSpace s1[i] then
nWords <- nWords + 1
printfn $"The sentence\n {s1}\nhas {nWords} words."
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
Module Example12
Public Sub Main()
Dim s1 As String = "This string consists of a single short sentence."
Dim nWords As Integer = 0
s1 = s1.Trim()
For ctr As Integer = 0 To s1.Length - 1
If Char.IsPunctuation(s1(ctr)) Or Char.IsWhiteSpace(s1(ctr)) Then
nWords += 1
End If
Next
Console.WriteLine("The sentence{2} {0}{2}has {1} words.",
s1, nWords, vbCrLf)
End Sub
End Module
' The example displays the following output:
' The sentence
' This string consists of a single short sentence.
' has 8 words.
Como a classe implementa a StringIEnumerable interface, você também pode iterar pelos Char objetos em uma cadeia de caracteres usando uma foreach
construção, como mostra o exemplo a seguir.
string s1 = "This string consists of a single short sentence.";
int nWords = 0;
s1 = s1.Trim();
foreach (var ch in s1) {
if (Char.IsPunctuation(ch) | Char.IsWhiteSpace(ch))
nWords++;
}
Console.WriteLine("The sentence\n {0}\nhas {1} words.",
s1, nWords);
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
let s1 = "This string consists of a single short sentence."
let mutable nWords = 0
for ch in s1 do
if Char.IsPunctuation ch || Char.IsWhiteSpace ch then
nWords <- nWords + 1
printfn $"The sentence\n {s1}\nhas {nWords} words."
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
Module Example13
Public Sub Main()
Dim s1 As String = "This string consists of a single short sentence."
Dim nWords As Integer = 0
s1 = s1.Trim()
For Each ch In s1
If Char.IsPunctuation(ch) Or Char.IsWhiteSpace(ch) Then
nWords += 1
End If
Next
Console.WriteLine("The sentence{2} {0}{2}has {1} words.",
s1, nWords, vbCrLf)
End Sub
End Module
' The example displays the following output:
' The sentence
' This string consists of a single short sentence.
' has 8 words.
Valores de índice consecutivos podem não corresponder a caracteres Unicode consecutivos, porque um caractere Unicode pode ser codificado como mais de um Char objeto. Em particular, uma cadeia de caracteres pode conter unidades de vários caracteres de texto que são formadas por um caractere base seguido por um ou mais caracteres combinados ou por pares substitutos. Para trabalhar com caracteres Unicode em vez de Char objetos, use as System.Globalization.StringInfo classes e ou o String.EnumerateRunes método e TextElementEnumerator a Rune struct. O exemplo a seguir ilustra a diferença entre o código que funciona com objetos e o código que funciona com Char caracteres Unicode. Ele compara o número de caracteres ou elementos de texto em cada palavra de uma frase. A cadeia de caracteres inclui duas sequências de um caractere base seguidas por um caractere combinado.
// 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
Este exemplo trabalha com elementos de texto usando o StringInfo.GetTextElementEnumerator método e a TextElementEnumerator classe para enumerar todos os elementos de texto em uma cadeia de caracteres. Você também pode recuperar uma matriz que contém o índice inicial de cada elemento de texto chamando o StringInfo.ParseCombiningCharacters método.
Para obter mais informações sobre como trabalhar com unidades de texto em vez de valores individuaisChar, consulte Introdução à codificação de caracteres no .NET.
Cadeias de caracteres nulas e cadeias de caracteres vazias
Uma cadeia de caracteres que foi declarada, mas não recebeu um valor é null
. A tentativa de chamar métodos nessa cadeia de caracteres lança um NullReferenceExceptionarquivo . Uma cadeia de caracteres nula é diferente de uma cadeia de caracteres vazia, que é uma cadeia de caracteres cujo valor é "" ou String.Empty. Em alguns casos, passar uma cadeia de caracteres nula ou uma cadeia de caracteres vazia como um argumento em uma chamada de método gera uma exceção. Por exemplo, passar uma cadeia de caracteres nula para o Int32.Parse método lança um , e passar uma cadeia de caracteres vazia lança um FormatExceptionArgumentNullExceptionarquivo . Em outros casos, um argumento de método pode ser uma cadeia de caracteres nula ou uma cadeia de caracteres vazia. Por exemplo, se você estiver fornecendo uma implementação para uma classe, você deseja equiparar uma cadeia de caracteres nula e uma IFormattable cadeia de caracteres vazia com o especificador de formato geral ("G").
A String classe inclui os dois métodos de conveniência a seguir que permitem testar se uma cadeia de caracteres está null
ou vazia:
IsNullOrEmpty, que indica se uma cadeia de caracteres é ou
null
é igual a String.Empty. Esse método elimina a necessidade de usar código como o seguinte: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, que indica se uma cadeia de caracteres é , é
null
igual String.Emptya , ou consiste exclusivamente em caracteres de espaço em branco. Esse método elimina a necessidade de usar código como o seguinte: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
O exemplo a seguir usa o IsNullOrEmptyIFormattable.ToString método na implementação de uma classe personalizada Temperature
. O método suporta as cadeias de caracteres de formato "G", "C", "F" e "K". Se uma cadeia de caracteres de formato vazia ou uma cadeia de caracteres de formato cujo valor é null
passado para o método, seu valor é alterado para a cadeia de caracteres de formato "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
Imutabilidade e a classe StringBuilder
Um String objeto é chamado de imutável (somente leitura), porque seu valor não pode ser modificado depois de criado. Os métodos que parecem modificar um objeto retornam um String novo String objeto que contém a modificação.
Como as cadeias de caracteres são imutáveis, as rotinas de manipulação de cadeias de caracteres que executam adições ou exclusões repetidas ao que parece ser uma única cadeia de caracteres podem exigir uma penalidade de desempenho significativa. Por exemplo, o código a seguir usa um gerador de números aleatórios para criar uma cadeia de caracteres com 1000 caracteres no intervalo 0x0001 para 0x052F. Embora o código pareça usar concatenação de cadeia de caracteres para acrescentar um novo caractere à cadeia de caracteres existente chamada str
, ele realmente cria um novo String objeto para cada operação de concatenação.
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
Você pode usar a StringBuilder classe em vez da String classe para operações que fazem várias alterações no valor de uma cadeia de caracteres. Ao contrário das instâncias da classe, os String objetos são mutáveis: quando você concatena, acrescenta ou exclui subcadeias de caracteres de uma cadeia de caracteres, StringBuilder as operações são executadas em uma única cadeia de caracteres. Quando terminar de modificar o valor de um StringBuilder objeto, você poderá chamar seu StringBuilder.ToString método para convertê-lo em uma cadeia de caracteres. O exemplo a seguir substitui o String usado no exemplo anterior para concatenar 1000 caracteres aleatórios no intervalo para 0x0001 a 0x052F com um StringBuilder objeto.
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
Ordinal x operações sensíveis à cultura
Os membros da String classe executam operações ordinais ou sensíveis à cultura (linguísticas) em um String objeto. Uma operação ordinal atua sobre o valor numérico de cada Char objeto. Uma operação sensível à cultura atua sobre o String valor do objeto e leva em consideração as regras de invólucro, classificação, formatação e análise específicas da cultura. As operações sensíveis à cultura são executadas no contexto de uma cultura explicitamente declarada ou da cultura atual implícita. Os dois tipos de operações podem produzir resultados muito diferentes quando são executadas na mesma cadeia de caracteres.
O .NET também oferece suporte a operações de cadeia de caracteres linguísticas sem diferenciação de cultura usando a cultura invariante (CultureInfo.InvariantCulture), que é vagamente baseada nas configurações de cultura do idioma inglês independente da região. Ao contrário de outras System.Globalization.CultureInfo configurações, as configurações da cultura invariante são garantidas para permanecer consistente em um único computador, de sistema para sistema e entre versões do .NET. A cultura invariante pode ser vista como uma espécie de caixa preta que garante a estabilidade das comparações de cordas e ordenação em todas as culturas.
Importante
Se seu aplicativo tomar uma decisão de segurança sobre um identificador simbólico, como um nome de arquivo ou pipe nomeado, ou sobre dados persistentes, como os dados baseados em texto em um arquivo XML, a operação deverá usar uma comparação ordinal em vez de uma comparação sensível à cultura. Isso ocorre porque uma comparação sensível à cultura pode produzir resultados diferentes dependendo da cultura em vigor, enquanto uma comparação ordinal depende exclusivamente do valor binário dos caracteres comparados.
Importante
A maioria dos métodos que executam operações de cadeia de caracteres inclui uma sobrecarga que tem um parâmetro do tipo StringComparison, que permite especificar se o método executa uma operação ordinal ou sensível à cultura. Em geral, você deve chamar essa sobrecarga para deixar clara a intenção da chamada do método. Para obter práticas recomendadas e orientação para usar operações ordinais e sensíveis à cultura em cadeias de caracteres, consulte Práticas recomendadas para usar cadeias de caracteres.
As operações para invólucro, análise e formatação, comparação e classificação e teste de igualdade podem ser ordinais ou sensíveis à cultura. As seções a seguir discutem cada categoria de operação.
Dica
Você deve sempre chamar uma sobrecarga de método que deixe clara a intenção da chamada de método. Por exemplo, em vez de chamar o método para executar uma comparação sensível à cultura de duas cadeias de caracteres usando as convenções da cultura atual, você deve chamar o método com um valor de StringComparison.CurrentCulture para o comparisonType
Compare(String, String)Compare(String, String, StringComparison) argumento. Para obter mais informações, consulte Práticas recomendadas para o uso de cadeias de caracteres.
Você pode baixar as tabelas de peso de classificação, um conjunto de arquivos de texto que contêm informações sobre os pesos de caracteres usados em operações de classificação e comparação, a partir dos seguintes links:
- Windows (.NET Framework e .NET Core): classificando tabelas de peso
- Atualização de maio de 2019 do Windows 10 ou posterior (.NET 5+) e Linux e macOS (.NET Core e .NET 5+): Tabela de elementos de agrupamento Unicode padrão
Capitalização
As regras de caixa determinam como alterar a capitalização de um caractere Unicode; por exemplo, de minúsculas para maiúsculas. Muitas vezes, uma operação de invólucro é executada antes de uma comparação de cadeia de caracteres. Por exemplo, uma cadeia de caracteres pode ser convertida em maiúsculas para que possa ser comparada com outra cadeia de caracteres maiúscula. Você pode converter os caracteres em uma cadeia de caracteres em minúsculas chamando o método or e convertê-los em maiúsculas chamando o ToLowerToUpper método ouToUpperInvariant.ToLowerInvariant Além disso, você pode usar o método para converter uma cadeia de caracteres em maiúsculas e minúsculas TextInfo.ToTitleCase de título.
Observação
.NET Core em execução somente nos sistemas Linux e macOS: o comportamento da ordenação das culturas C e Posix é sempre sensível a maiúsculas e minúsculas porque essas culturas não usam a ordem da Ordenação Unicode esperada. Recomendamos usar uma cultura diferente de C ou Posix para executar operações de classificação que diferenciam culturas e maiúsculas de minúsculas.
As operações de invólucro podem ser baseadas nas regras da cultura atual, de uma cultura especificada ou da cultura invariante. Como os mapeamentos de caso podem variar dependendo da cultura usada, o resultado das operações de invólucro pode variar com base na cultura. As diferenças reais no invólucro são de três tipos:
Diferenças no mapeamento de casos de LETRA MAIÚSCULA LATINA I (U+0049), LETRA PEQUENA LATINA I (U+0069), LETRA MAIÚSCULA LATINA I COM PONTO ACIMA (U+0130) e LETRA PEQUENA LATINA SEM PONTO I (U+0131). Nas culturas tr-TR (turco (Turquia)) e az-Latn-AZ (Azerbaijão, latim), e nas culturas neutras tr, az e az-Latn, o equivalente minúsculo de LETRA MAIÚSCULA LATINA I é LETRA PEQUENA LATINA SEM PONTO I, e o equivalente maiúsculo de LETRA PEQUENA LATINA I é LETRA MAIÚSCULA LATINA I COM PONTO ACIMA. Em todas as outras culturas, incluindo a cultura invariante, LETRA PEQUENA LATINA I e LETRA MAIÚSCULA LATINA I são equivalentes minúsculas e maiúsculas.
O exemplo a seguir demonstra como uma comparação de cadeia de caracteres projetada para impedir o acesso ao sistema de arquivos pode falhar se depender de uma comparação de caixa sensível à cultura. (As convenções de invólucro da cultura invariante deveriam ter sido usadas.)
using System; using System.Globalization; using System.Threading; public class Example1 { const string disallowed = "file"; public static void Main() { IsAccessAllowed(@"FILE:\\\c:\users\user001\documents\FinancialInfo.txt"); } private static void IsAccessAllowed(String resource) { CultureInfo[] cultures = { CultureInfo.CreateSpecificCulture("en-US"), CultureInfo.CreateSpecificCulture("tr-TR") }; String scheme = null; int index = resource.IndexOfAny( new Char[] { '\\', '/' } ); if (index > 0) scheme = resource.Substring(0, index - 1); // Change the current culture and perform the comparison. foreach (var culture in cultures) { Thread.CurrentThread.CurrentCulture = culture; Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName); Console.WriteLine(resource); Console.WriteLine("Access allowed: {0}", ! String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase)); Console.WriteLine(); } } } // The example displays the following output: // Culture: English (United States) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: False // // Culture: Turkish (Turkey) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: True
open System open System.Globalization open System.Threading let disallowed = "file" let isAccessAllowed (resource: string) = let cultures = [| CultureInfo.CreateSpecificCulture "en-US" CultureInfo.CreateSpecificCulture "tr-TR" |] let index = resource.IndexOfAny [| '\\'; '/' |] let scheme = if index > 0 then resource.Substring(0, index - 1) else null // Change the current culture and perform the comparison. for culture in cultures do Thread.CurrentThread.CurrentCulture <- culture printfn $"Culture: {CultureInfo.CurrentCulture.DisplayName}" printfn $"{resource}" printfn $"Access allowed: {String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase) |> not}" printfn "" isAccessAllowed @"FILE:\\\c:\users\user001\documents\FinancialInfo.txt" // The example displays the following output: // Culture: English (United States) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: False // // Culture: Turkish (Turkey) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: True
Imports System.Globalization Imports System.Threading Module Example2 Const disallowed = "file" Public Sub Main() IsAccessAllowed("FILE:\\\c:\users\user001\documents\FinancialInfo.txt") End Sub Private Sub IsAccessAllowed(resource As String) Dim cultures() As CultureInfo = {CultureInfo.CreateSpecificCulture("en-US"), CultureInfo.CreateSpecificCulture("tr-TR")} Dim scheme As String = Nothing Dim index As Integer = resource.IndexOfAny({"\"c, "/"c}) If index > 0 Then scheme = resource.Substring(0, index - 1) ' Change the current culture and perform the comparison. For Each culture In cultures Thread.CurrentThread.CurrentCulture = culture Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName) Console.WriteLine(resource) Console.WriteLine("Access allowed: {0}", Not String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase)) Console.WriteLine() Next End Sub End Module ' The example displays the following output: ' Culture: English (United States) ' FILE:\\\c:\users\user001\documents\FinancialInfo.txt ' Access allowed: False ' ' Culture: Turkish (Turkey) ' FILE:\\\c:\users\user001\documents\FinancialInfo.txt ' Access allowed: True
Diferenças nos mapeamentos de casos entre a cultura invariante e todas as outras culturas. Nesses casos, usar as regras de caixa da cultura invariante para alterar um caractere para maiúsculas ou minúsculas retorna o mesmo caractere. Para todas as outras culturas, devolve um caráter diferente. Alguns dos caracteres afetados estão listados na tabela a seguir.
Character Se alterado para Retornos SINAL DE MÍCRON (U+00B5) Maiúsculas LETRA MAIÚSCULA GREGA MU (U+-39C) LETRA MAIÚSCULA LATINA I COM PONTO ACIMA (U+0130) Letras minúsculas LETRA PEQUENA LATINA I (U+0069) LETRA PEQUENA LATINA SEM PONTO I (U+0131) Maiúsculas LETRA MAIÚSCULA LATINA I (U+0049) LETRA PEQUENA LATINA S LONGAS (U+017F) Maiúsculas LETRA S MAIÚSCULA LATINA (U+0053) LETRA D MAIÚSCULA LATINA COM LETRA Z PEQUENA COM CARON (U+01C5) Letras minúsculas LETRA PEQUENA LATINA DZ COM CARON (U+01C6) COMBINANDO YPOGEGRAMMENI GREGO (U+0345) Maiúsculas LETRA MAIÚSCULA GREGA IOTA (U+0399) Diferenças nos mapeamentos de maiúsculas e minúsculas de pares de maiúsculas e minúsculas no intervalo de caracteres ASCII. Na maioria das culturas, um par de letras maiúsculas e minúsculas é igual ao par equivalente de duas letras maiúsculas ou minúsculas. Isso não é verdade para os seguintes pares de duas letras nas seguintes culturas, porque em cada caso eles são comparados a um dígrafo:
- "lJ" e "nJ" na cultura hr-HR (croata (Croácia)).
- "cH" nas culturas cs-CZ (República Checa (República Checa)) e sk-SK (Eslovaco (Eslováquia)).
- "aA" na cultura da-DK (dinamarquesa (Dinamarca)).
- "cS", "dZ", "dZS", "nY", "sZ", "tY" e "zS" na cultura hu-HU (Hungria).
- "cH" e "lL" na cultura es-ES_tradnl (Espanhol (Espanha, Classificação Tradicional)).
- "cH", "gI", "kH", "nG" "nH", "pH", "qU', "tH" e "tR" na cultura vi-VN (vietnamita (Vietnã)).
No entanto, é incomum encontrar uma situação em que uma comparação sensível à cultura desses pares crie problemas, porque esses pares são incomuns em cadeias de caracteres fixas ou identificadores.
O exemplo a seguir ilustra algumas das diferenças nas regras de invólucro entre culturas ao converter cadeias de caracteres em maiúsculas.
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
Análise e formatação
Formatação e análise são operações inversas. As regras de formatação determinam como converter um valor, como uma data e hora ou um número, em sua representação de cadeia de caracteres, enquanto as regras de análise determinam como converter uma representação de cadeia de caracteres em um valor como uma data e hora. As regras de formatação e análise dependem de convenções culturais. O exemplo a seguir ilustra a ambiguidade que pode surgir ao interpretar uma cadeia de caracteres de data específica da cultura. Sem conhecer as convenções da cultura que foi utilizada para produzir uma sequência de datas, não é possível saber se 01/03/2011, 01/03/2011 e 01/03/2011 representam 3 de janeiro de 2011 ou 1º de março de 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
Da mesma forma, como mostra o exemplo a seguir, uma única cadeia de caracteres pode produzir datas diferentes, dependendo da cultura cujas convenções são usadas na operação de análise.
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
Comparação da cadeia de caracteres e classificação
As convenções para comparar e classificar cadeias de caracteres variam de cultura para cultura. Por exemplo, a ordem de classificação pode ser baseada na fonética ou na representação visual de caracteres. Nos idiomas do leste asiático, os caracteres são ordenados pelo traço e pelo radical dos ideogramas. A classificação também depende da ordem em que os idiomas e culturas usam para o alfabeto. Por exemplo, a língua dinamarquesa tem um caractere "Æ" que é ordenado após a letra "Z" no alfabeto. Além disso, as comparações podem diferenciar maiúsculas de minúsculas ou diferenciar maiúsculas de minúsculas, e as regras de invólucro podem diferir de acordo com a cultura. A comparação ordinal, por outro lado, usa os pontos de código Unicode de caracteres individuais em uma cadeia de caracteres ao comparar e classificar cadeias de caracteres.
As regras de classificação determinam a ordem alfabética dos caracteres Unicode e como duas cadeias de caracteres se comparam entre si. Por exemplo, o String.Compare(String, String, StringComparison) método compara duas cadeias de caracteres com base no StringComparison parâmetro. Se o valor do parâmetro for , o método executará uma comparação linguística que usa as convenções da cultura atual, se o valor do parâmetro for StringComparison.CurrentCultureStringComparison.Ordinal, o método executará uma comparação ordinal. Consequentemente, como mostra o exemplo a seguir, se a cultura atual é o inglês dos EUA, a primeira chamada para o método (usando comparação sensível à cultura) considera "a" menor que "A", mas a segunda chamada para o String.Compare(String, String, StringComparison) mesmo método (usando comparação ordinal) considera "a" maior que "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
O .NET oferece suporte a regras de classificação de palavras, cadeias de caracteres e ordinais:
Uma classificação de palavras executa uma comparação cultural de cadeias de caracteres nas quais determinados caracteres Unicode não alfanuméricos podem ter pesos especiais atribuídos a eles. Por exemplo, o hífen (-) pode ter um peso muito pequeno atribuído a ele para que "coop" e "co-op" apareçam um ao lado do outro em uma lista classificada. Para obter uma lista dos métodos que comparam duas cadeias de caracteres usando regras de classificação de palavras, consulte a seção Operações de cadeia de String caracteres por categoria.
Uma classificação de cadeia de caracteres também executa uma comparação sensível à cultura. É semelhante a uma classificação de palavras, exceto que não há casos especiais, e todos os símbolos não alfanuméricos vêm antes de todos os caracteres Unicode alfanuméricos. Duas cadeias de caracteres podem ser comparadas usando regras de classificação de cadeia de caracteres chamando as CompareInfo.Compare sobrecargas de método que têm um parâmetro fornecido com um
options
valor de CompareOptions.StringSort. Observe que esse é o único método que o .NET fornece para comparar duas cadeias de caracteres usando regras de classificação de cadeia de caracteres.Uma classificação ordinal compara cadeias de caracteres com base no valor numérico de cada Char objeto na cadeia de caracteres. Uma comparação ordinal diferencia automaticamente maiúsculas de minúsculas porque as versões minúsculas e maiúsculas de um caractere têm pontos de código diferentes. No entanto, se maiúsculas e minúsculas não forem importantes, você poderá especificar uma comparação ordinal que ignore maiúsculas e minúsculas. Isso equivale a converter a cadeia de caracteres em maiúsculas usando a cultura invariante e, em seguida, executando uma comparação ordinal no resultado. Para obter uma lista dos métodos que comparam duas cadeias de caracteres usando regras de classificação ordinais, consulte a seção Operações de cadeia de String caracteres por categoria.
Uma comparação sensível à cultura é qualquer comparação que usa explícita ou implicitamente um CultureInfo objeto, incluindo a cultura invariante especificada pela CultureInfo.InvariantCulture propriedade. A cultura implícita é a cultura atual, que é especificada pelas Thread.CurrentCulture propriedades e CultureInfo.CurrentCulture . Há uma variação considerável na ordem de classificação dos caracteres alfabéticos (ou seja, caracteres para os quais a Char.IsLetter propriedade retorna true
) entre culturas. Você pode especificar uma comparação sensível à cultura que usa as convenções de uma cultura específica fornecendo um objeto para um CultureInfo método de comparação de cadeia de caracteres, como Compare(String, String, CultureInfo, CompareOptions). Você pode especificar uma comparação sensível à cultura que usa as convenções da cultura atual fornecendo StringComparison.CurrentCulture, StringComparison.CurrentCultureIgnoreCaseou qualquer membro da CompareOptions enumeração que não seja CompareOptions.Ordinal ou CompareOptions.OrdinalIgnoreCase para uma sobrecarga apropriada do Compare método. Uma comparação sensível à cultura é geralmente apropriada para classificação, enquanto uma comparação ordinal não é. Uma comparação ordinal é geralmente apropriada para determinar se duas cadeias de caracteres são iguais (isto é, para determinar a identidade), enquanto uma comparação sensível à cultura não é.
O exemplo a seguir ilustra a diferença entre comparação cultural e ordinal. O exemplo avalia três cadeias de caracteres, "Apple", "Æble" e "AEble", usando comparação ordinal e as convenções das culturas da-DK e en-US (cada uma das quais é a cultura padrão no momento em que o Compare método é chamado). Como a língua dinamarquesa trata o caractere "Æ" como uma letra individual e o classifica após "Z" no alfabeto, a cadeia "Æble" é maior que "Apple". No entanto, "Æble" não é considerado equivalente a "AEble", então "Æble" também é maior que "AEble". A cultura en-US não inclui a letra "Æ", mas a trata como equivalente a "AE", o que explica por que "Æble" é menor que "Apple", mas igual a "AEble". A comparação ordinal, por outro lado, considera "Apple" menor que "Æble", e "Æble" maior que "AEble".
using System;
using System.Globalization;
using System.Threading;
public class CompareStringSample
{
public static void Main()
{
string str1 = "Apple";
string str2 = "Æble";
string str3 = "AEble";
// Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name);
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2));
Console.WriteLine("Comparison of {0} with {1}: {2}\n",
str2, str3, String.Compare(str2, str3));
// Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name);
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2));
Console.WriteLine("Comparison of {0} with {1}: {2}\n",
str2, str3, String.Compare(str2, str3));
// Perform an ordinal comparison.
Console.WriteLine("Ordinal comparison");
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2,
String.Compare(str1, str2, StringComparison.Ordinal));
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3,
String.Compare(str2, str3, StringComparison.Ordinal));
}
}
// The example displays the following output:
// Current culture: da-DK
// Comparison of Apple with Æble: -1
// Comparison of Æble with AEble: 1
//
// Current culture: en-US
// Comparison of Apple with Æble: 1
// Comparison of Æble with AEble: 0
//
// Ordinal comparison
// Comparison of Apple with Æble: -133
// Comparison of Æble with AEble: 133
open System
open System.Globalization
open System.Threading
let str1 = "Apple"
let str2 = "Æble"
let str3 = "AEble"
// Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture <- CultureInfo "da-DK"
printfn $"Current culture: {CultureInfo.CurrentCulture.Name}"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n"
// Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture <- CultureInfo "en-US"
printfn $"Current culture: {CultureInfo.CurrentCulture.Name}"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n"
// Perform an ordinal comparison.
printfn "Ordinal comparison"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2, StringComparison.Ordinal)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3, StringComparison.Ordinal)}"
// The example displays the following output:
// Current culture: da-DK
// Comparison of Apple with Æble: -1
// Comparison of Æble with AEble: 1
//
// Current culture: en-US
// Comparison of Apple with Æble: 1
// Comparison of Æble with AEble: 0
//
// Ordinal comparison
// Comparison of Apple with Æble: -133
// Comparison of Æble with AEble: 133
Imports System.Globalization
Imports System.Threading
Public Module Example6
Public Sub Main()
Dim str1 As String = "Apple"
Dim str2 As String = "Æble"
Dim str3 As String = "AEble"
' Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture = New CultureInfo("da-DK")
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name)
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2))
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3, String.Compare(str2, str3))
Console.WriteLine()
' Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name)
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2))
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3, String.Compare(str2, str3))
Console.WriteLine()
' Perform an ordinal comparison.
Console.WriteLine("Ordinal comparison")
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2,
String.Compare(str1, str2, StringComparison.Ordinal))
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3,
String.Compare(str2, str3, StringComparison.Ordinal))
End Sub
End Module
' The example displays the following output:
' Current culture: da-DK
' Comparison of Apple with Æble: -1
' Comparison of Æble with AEble: 1
'
' Current culture: en-US
' Comparison of Apple with Æble: 1
' Comparison of Æble with AEble: 0
'
' Ordinal comparison
' Comparison of Apple with Æble: -133
' Comparison of Æble with AEble: 133
Use as seguintes diretrizes gerais para escolher um método apropriado de classificação ou comparação de cadeia de caracteres:
Se você quiser que as cadeias de caracteres sejam ordenadas com base na cultura do usuário, você deve ordená-las com base nas convenções da cultura atual. Se a cultura do usuário for alterada, a ordem das cadeias de caracteres classificadas também será alterada de acordo. Por exemplo, um aplicativo de dicionário de sinônimos deve sempre classificar palavras com base na cultura do usuário.
Se desejar que as cadeias de caracteres sejam ordenadas com base nas convenções de uma cultura específica, você deve ordená-las fornecendo um objeto que represente essa cultura para um CultureInfo método de comparação. Por exemplo, em um aplicativo projetado para ensinar aos alunos um idioma específico, você deseja que as cadeias de caracteres sejam ordenadas com base nas convenções de uma das culturas que fala esse idioma.
Se quiser que a ordem das cadeias de caracteres permaneça inalterada entre culturas, você deve ordená-las com base nas convenções da cultura invariante ou usar uma comparação ordinal. Por exemplo, você usaria uma classificação ordinal para organizar os nomes de arquivos, processos, mutexes ou pipes nomeados.
Para uma comparação que envolve uma decisão de segurança (como se um nome de usuário é válido), você deve sempre executar um teste ordinal para igualdade chamando uma sobrecarga do Equals método.
Observação
As regras de classificação e invólucro sensíveis à cultura usadas na comparação de cadeias de caracteres dependem da versão do .NET. No .NET Core, a comparação de cadeia de caracteres depende da versão do padrão Unicode suportada pelo sistema operacional subjacente. No .NET Framework 4.5 e versões posteriores em execução no Windows 8 ou posterior, as informações de classificação, invólucro, normalização e caracteres Unicode estão em conformidade com o padrão Unicode 6.0. Em outros sistemas operacionais Windows, eles estão em conformidade com o padrão Unicode 5.0.
Para obter mais informações sobre regras de classificação de palavra, cadeia de caracteres e ordinal, consulte o System.Globalization.CompareOptions tópico . Para obter recomendações adicionais sobre quando usar cada regra, consulte Práticas recomendadas para usar cadeias de caracteres.
Normalmente, você não chama métodos de comparação de cadeias de caracteres, como Compare diretamente, para determinar a ordem de classificação das cadeias de caracteres. Em vez disso, os métodos de comparação são chamados por métodos de classificação como Array.Sort ou List<T>.Sort. O exemplo a seguir executa quatro operações de classificação diferentes (classificação de palavras usando a cultura atual, classificação de palavras usando a cultura invariante, classificação ordinal e classificação de cadeia de caracteres usando a cultura invariante) sem chamar explicitamente um método de comparação de cadeia de caracteres, embora eles especifiquem o tipo de comparação a ser usado. Observe que cada tipo de classificação produz uma ordem exclusiva de cadeias de caracteres em sua matriz.
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
// cooperative co-op co-op cooperative coop
// cœur cooperative cooperative cooperative cooperative
// coeur cooperative cooperative cœur cooperative
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
// cooperative co-op co-op cooperative coop
// cœur cooperative cooperative cooperative cooperative
// coeur cooperative cooperative cœur cooperative
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
' cooperative co-op co-op cooperative coop
' cœur cooperative cooperative cooperative cooperative
' coeur cooperative cooperative cœur cooperative
Dica
Internamente, o .NET usa chaves de classificação para oferecer suporte à comparação de cadeias de caracteres culturalmente sensíveis. Cada caractere em uma cadeia de caracteres recebe várias categorias de pesos de classificação, incluindo alfabética, maiúsculas e minúsculas e diacríticas. Uma chave de classificação, representada pela SortKey classe, fornece um repositório desses pesos para uma cadeia de caracteres específica. Se seu aplicativo executar um grande número de operações de pesquisa ou classificação no mesmo conjunto de cadeias de caracteres, você poderá melhorar seu desempenho gerando e armazenando chaves de classificação para todas as cadeias de caracteres que ele usa. Quando uma operação de classificação ou comparação é necessária, use as chaves de classificação em vez das cadeias de caracteres. Para obter mais informações, consulte a classe SortKey.
Se você não especificar uma convenção de comparação de cadeia de caracteres, métodos de classificação, como Array.Sort(Array) executar uma classificação sensível a maiúsculas e minúsculas em cadeias de caracteres. O exemplo a seguir ilustra como a alteração da cultura atual afeta a ordem das cadeias de caracteres classificadas em uma matriz. Ele cria uma matriz de três cadeias de caracteres. Primeiro, ele define a System.Threading.Thread.CurrentThread.CurrentCulture
propriedade como en-US e chama o Array.Sort(Array) método. A ordem de classificação resultante é baseada em convenções de classificação para a cultura inglesa (Estados Unidos). Em seguida, o exemplo define a System.Threading.Thread.CurrentThread.CurrentCulture
propriedade como da-DK e chama o Array.Sort método novamente. Observe como a ordem de classificação resultante difere dos resultados en-US porque usa as convenções de classificação para dinamarquês (Dinamarca).
using System;
using System.Globalization;
using System.Threading;
public class ArraySort
{
public static void Main(String[] args)
{
// Create and initialize a new array to store the strings.
string[] stringArray = { "Apple", "Æble", "Zebra"};
// Display the values of the array.
Console.WriteLine( "The original string array:");
PrintIndexAndValues(stringArray);
// Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
// Sort the values of the array.
Array.Sort(stringArray);
// Display the values of the array.
Console.WriteLine("After sorting for the culture \"en-US\":");
PrintIndexAndValues(stringArray);
// Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");
// Sort the values of the Array.
Array.Sort(stringArray);
// Display the values of the array.
Console.WriteLine("After sorting for the culture \"da-DK\":");
PrintIndexAndValues(stringArray);
}
public static void PrintIndexAndValues(string[] myArray)
{
for (int i = myArray.GetLowerBound(0); i <=
myArray.GetUpperBound(0); i++ )
Console.WriteLine("[{0}]: {1}", i, myArray[i]);
Console.WriteLine();
}
}
// The example displays the following output:
// The original string array:
// [0]: Apple
// [1]: Æble
// [2]: Zebra
//
// After sorting for the "en-US" culture:
// [0]: Æble
// [1]: Apple
// [2]: Zebra
//
// After sorting for the culture "da-DK":
// [0]: Apple
// [1]: Zebra
// [2]: Æble
open System
open System.Globalization
open System.Threading
let printIndexAndValues (myArray: string[]) =
for i = myArray.GetLowerBound 0 to myArray.GetUpperBound 0 do
printfn $"[{i}]: {myArray[i]}"
printfn ""
// Create and initialize a new array to store the strings.
let stringArray = [| "Apple"; "Æble"; "Zebra" |]
// Display the values of the array.
printfn "The original string array:"
printIndexAndValues stringArray
// Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture <- CultureInfo "en-US"
// Sort the values of the array.
Array.Sort stringArray
// Display the values of the array.
printfn "After sorting for the culture \"en-US\":"
printIndexAndValues stringArray
// Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture <- CultureInfo "da-DK"
// Sort the values of the Array.
Array.Sort stringArray
// Display the values of the array.
printfn "After sorting for the culture \"da-DK\":"
printIndexAndValues stringArray
// The example displays the following output:
// The original string array:
// [0]: Apple
// [1]: Æble
// [2]: Zebra
//
// After sorting for the "en-US" culture:
// [0]: Æble
// [1]: Apple
// [2]: Zebra
//
// After sorting for the culture "da-DK":
// [0]: Apple
// [1]: Zebra
// [2]: Æble
Imports System.Globalization
Imports System.IO
Imports System.Threading
Public Class TextToFile
Public Shared Sub Main()
' Creates and initializes a new array to store
' these date/time objects.
Dim stringArray() As String = { "Apple", "Æble", "Zebra"}
' Displays the values of the array.
Console.WriteLine("The original string array:")
PrintIndexAndValues(stringArray)
' Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
' Sort the values of the Array.
Array.Sort(stringArray)
' Display the values of the array.
Console.WriteLine("After sorting for the ""en-US"" culture:")
PrintIndexAndValues(stringArray)
' Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture = New CultureInfo("da-DK")
' Sort the values of the Array.
Array.Sort(stringArray)
' Displays the values of the Array.
Console.WriteLine("After sorting for the culture ""da-DK"":")
PrintIndexAndValues(stringArray)
End Sub
Public Shared Sub PrintIndexAndValues(myArray() As String)
For i As Integer = myArray.GetLowerBound(0) To myArray.GetUpperBound(0)
Console.WriteLine("[{0}]: {1}", i, myArray(i))
Next
Console.WriteLine()
End Sub
End Class
' The example displays the following output:
' The original string array:
' [0]: Apple
' [1]: Æble
' [2]: Zebra
'
' After sorting for the "en-US" culture:
' [0]: Æble
' [1]: Apple
' [2]: Zebra
'
' After sorting for the culture "da-DK":
' [0]: Apple
' [1]: Zebra
' [2]: Æble
Aviso
Se o seu objetivo principal ao comparar cadeias de caracteres é determinar se elas são iguais, você deve chamar o String.Equals método. Normalmente, você deve usar Equals para executar uma comparação ordinal. O String.Compare método destina-se principalmente a classificar cadeias de caracteres.
Os métodos de pesquisa de cadeia de caracteres, como String.StartsWith e String.IndexOf, também podem executar comparações de cadeia de caracteres ordinais ou sensíveis à cultura. O exemplo a seguir ilustra as diferenças entre comparações ordinais e sensíveis à cultura usando o IndexOf método. Uma pesquisa sensível à cultura em que a cultura atual é o inglês (Estados Unidos) considera a substring "oe" para corresponder à ligadura "œ". Como um hífen suave (U+00AD) é um caractere de largura zero, a pesquisa trata o hífen suave como equivalente e String.Empty localiza uma correspondência no início da cadeia de caracteres. Uma busca ordinal, por outro lado, não encontra correspondência em nenhum dos casos.
using System;
public class Example8
{
public static void Main()
{
// Search for "oe" and "œu" in "œufs" and "oeufs".
string s1 = "œufs";
string s2 = "oeufs";
FindInString(s1, "oe", StringComparison.CurrentCulture);
FindInString(s1, "oe", StringComparison.Ordinal);
FindInString(s2, "œu", StringComparison.CurrentCulture);
FindInString(s2, "œu", StringComparison.Ordinal);
Console.WriteLine();
string s3 = "co\u00ADoperative";
FindInString(s3, "\u00AD", StringComparison.CurrentCulture);
FindInString(s3, "\u00AD", StringComparison.Ordinal);
}
private static void FindInString(string s, string substring, StringComparison options)
{
int result = s.IndexOf(substring, options);
if (result != -1)
Console.WriteLine("'{0}' found in {1} at position {2}",
substring, s, result);
else
Console.WriteLine("'{0}' not found in {1}",
substring, s);
}
}
// The example displays the following output:
// 'oe' found in œufs at position 0
// 'oe' not found in œufs
// 'œu' found in oeufs at position 0
// 'œu' not found in oeufs
//
// '' found in cooperative at position 0
// '' found in cooperative 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 cooperative at position 0
// '' found in cooperative 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 cooperative at position 0
' '' found in cooperative at position 2
Pesquisar em cadeias de caracteres
Os métodos de pesquisa de cadeia de caracteres, como String.StartsWith e , também podem executar comparações de cadeia de caracteres ordinais ou sensíveis à cultura para determinar se um caractere String.IndexOfou subcadeia de caracteres é encontrado em uma cadeia de caracteres especificada.
Os métodos de pesquisa na String classe que procuram um caractere individual, como o método, ou um de um conjunto de caracteres, como o IndexOfIndexOfAny método, todos executam uma pesquisa ordinal. Para executar uma pesquisa sensível à cultura para um caractere, você deve chamar um CompareInfo método como CompareInfo.IndexOf(String, Char) ou CompareInfo.LastIndexOf(String, Char). Observe que os resultados da busca por um caractere usando comparação ordinal e sensível à cultura podem ser muito diferentes. Por exemplo, uma busca por um caractere Unicode pré-composto, como a ligadura "Æ" (U+00C6), pode corresponder a qualquer ocorrência de seus componentes na sequência correta, como "AE" (U+041U+0045), dependendo da cultura. O exemplo a seguir ilustra a diferença entre os String.IndexOf(Char) métodos e ao procurar um caractere CompareInfo.IndexOf(String, Char) individual. A ligadura "æ" (U+00E6) é encontrada na cadeia "aérea" quando se usa as convenções da cultura en-US, mas não quando se usa as convenções da cultura da-DK ou quando se realiza uma comparação ordinal.
using System;
using System.Globalization;
public class Example17
{
public static void Main()
{
String[] cultureNames = { "da-DK", "en-US" };
CompareInfo ci;
String str = "aerial";
Char ch = 'æ'; // U+00E6
Console.Write("Ordinal comparison -- ");
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
str.IndexOf(ch));
foreach (var cultureName in cultureNames) {
ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo;
Console.Write("{0} cultural comparison -- ", cultureName);
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
ci.IndexOf(str, ch));
}
}
}
// The example displays the following output:
// Ordinal comparison -- Position of 'æ' in aerial: -1
// da-DK cultural comparison -- Position of 'æ' in aerial: -1
// en-US cultural comparison -- Position of 'æ' in aerial: 0
open System.Globalization
let cultureNames = [| "da-DK"; "en-US" |]
let str = "aerial"
let ch = 'æ' // U+00E6
printf "Ordinal comparison -- "
printfn $"Position of '{ch}' in {str}: {str.IndexOf ch}"
for cultureName in cultureNames do
let ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo
printf $"{cultureName} cultural comparison -- "
printfn $"Position of '{ch}' in {str}: {ci.IndexOf(str, ch)}"
// The example displays the following output:
// Ordinal comparison -- Position of 'æ' in aerial: -1
// da-DK cultural comparison -- Position of 'æ' in aerial: -1
// en-US cultural comparison -- Position of 'æ' in aerial: 0
Imports System.Globalization
Module Example19
Public Sub Main()
Dim cultureNames() As String = {"da-DK", "en-US"}
Dim ci As CompareInfo
Dim str As String = "aerial"
Dim ch As Char = "æ"c ' U+00E6
Console.Write("Ordinal comparison -- ")
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
str.IndexOf(ch))
For Each cultureName In cultureNames
ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo
Console.Write("{0} cultural comparison -- ", cultureName)
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
ci.IndexOf(str, ch))
Next
End Sub
End Module
' The example displays the following output:
' Ordinal comparison -- Position of 'æ' in aerial: -1
' da-DK cultural comparison -- Position of 'æ' in aerial: -1
' en-US cultural comparison -- Position of 'æ' in aerial: 0
Por outro lado, String os métodos de classe que procuram uma cadeia de caracteres em vez de um caractere executam uma pesquisa sensível à cultura se as opções de pesquisa não forem explicitamente especificadas por um parâmetro do tipo StringComparison. A única exceção é Contains, que realiza uma pesquisa ordinal.
Teste de igualdade
Use o String.Compare método para determinar a relação de duas cadeias de caracteres na ordem de classificação. Normalmente, essa é uma operação sensível à cultura. Em contrapartida, chame o método para testar a String.Equals igualdade. Como o teste de igualdade geralmente compara a entrada do usuário com alguma cadeia de caracteres conhecida, como um nome de usuário válido, uma senha ou um caminho do sistema de arquivos, normalmente é uma operação ordinal.
Aviso
É possível testar a igualdade chamando o método e determinando se o String.Compare valor de retorno é zero. No entanto, essa prática não é recomendada. Para determinar se duas cadeias de caracteres são iguais, você deve chamar uma das sobrecargas do String.Equals método. A sobrecarga preferencial a ser chamada é o método de instância Equals(String, StringComparison) ou o método estático Equals(String, String, StringComparison) , porque ambos os métodos incluem um System.StringComparison parâmetro que especifica explicitamente o tipo de comparação.
O exemplo a seguir ilustra o perigo de realizar uma comparação sensível à cultura para igualdade quando uma ordinal deve ser usada em vez disso. Nesse caso, a intenção do código é proibir o acesso ao sistema de arquivos de URLs que começam com "FILE://" ou "file://", realizando uma comparação sem diferenciação de maiúsculas e minúsculas do início de uma URL com a cadeia de caracteres "FILE://". No entanto, se uma comparação sensível à cultura for realizada usando a cultura turca (Turquia) em uma URL que começa com "file://", a comparação para igualdade falhará, porque o equivalente turco maiúsculo do "i" minúsculo é "İ" em vez de "I". Como resultado, o acesso ao sistema de arquivos é permitido inadvertidamente. Por outro lado, se uma comparação ordinal for realizada, a comparação para igualdade será bem-sucedida e o acesso ao sistema de arquivos será negado.
using System;
using System.Globalization;
using System.Threading;
public class Example4
{
public static void Main()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR");
string filePath = "file://c:/notes.txt";
Console.WriteLine("Culture-sensitive test for equality:");
if (! TestForEquality(filePath, StringComparison.CurrentCultureIgnoreCase))
Console.WriteLine("Access to {0} is allowed.", filePath);
else
Console.WriteLine("Access to {0} is not allowed.", filePath);
Console.WriteLine("\nOrdinal test for equality:");
if (! TestForEquality(filePath, StringComparison.OrdinalIgnoreCase))
Console.WriteLine("Access to {0} is allowed.", filePath);
else
Console.WriteLine("Access to {0} is not allowed.", filePath);
}
private static bool TestForEquality(string str, StringComparison cmp)
{
int position = str.IndexOf("://");
if (position < 0) return false;
string substring = str.Substring(0, position);
return substring.Equals("FILE", cmp);
}
}
// The example displays the following output:
// Culture-sensitive test for equality:
// Access to file://c:/notes.txt is allowed.
//
// Ordinal test for equality:
// Access to file://c:/notes.txt is not allowed.
open System
open System.Globalization
open System.Threading
let testForEquality (str: string) (cmp: StringComparison) =
let position = str.IndexOf "://"
if position < 0 then false
else
let substring = str.Substring(0, position)
substring.Equals("FILE", cmp)
Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "tr-TR"
let filePath = "file://c:/notes.txt"
printfn "Culture-sensitive test for equality:"
if not (testForEquality filePath StringComparison.CurrentCultureIgnoreCase) then
printfn $"Access to {filePath} is allowed."
else
printfn $"Access to {filePath} is not allowed."
printfn "\nOrdinal test for equality:"
if not (testForEquality filePath StringComparison.OrdinalIgnoreCase) then
printfn $"Access to {filePath} is allowed."
else
printfn $"Access to {filePath} is not allowed."
// The example displays the following output:
// Culture-sensitive test for equality:
// Access to file://c:/notes.txt is allowed.
//
// Ordinal test for equality:
// Access to file://c:/notes.txt is not allowed.
Imports System.Globalization
Imports System.Threading
Module Example7
Public Sub Main()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR")
Dim filePath As String = "file://c:/notes.txt"
Console.WriteLine("Culture-sensitive test for equality:")
If Not TestForEquality(filePath, StringComparison.CurrentCultureIgnoreCase) Then
Console.WriteLine("Access to {0} is allowed.", filePath)
Else
Console.WriteLine("Access to {0} is not allowed.", filePath)
End If
Console.WriteLine()
Console.WriteLine("Ordinal test for equality:")
If Not TestForEquality(filePath, StringComparison.OrdinalIgnoreCase) Then
Console.WriteLine("Access to {0} is allowed.", filePath)
Else
Console.WriteLine("Access to {0} is not allowed.", filePath)
End If
End Sub
Private Function TestForEquality(str As String, cmp As StringComparison) As Boolean
Dim position As Integer = str.IndexOf("://")
If position < 0 Then Return False
Dim substring As String = str.Substring(0, position)
Return substring.Equals("FILE", cmp)
End Function
End Module
' The example displays the following output:
' Culture-sensitive test for equality:
' Access to file://c:/notes.txt is allowed.
'
' Ordinal test for equality:
' Access to file://c:/notes.txt is not allowed.
Normalização
Alguns caracteres Unicode têm várias representações. Por exemplo, qualquer um dos seguintes pontos de código pode representar a letra "ắ":
- U+1EAF
- U+0103 U+0301
- U+0061 U+0306 U+0301
Várias representações para um único caractere complicam a pesquisa, a classificação, a correspondência e outras operações de cadeia de caracteres.
O padrão Unicode define um processo chamado normalização que retorna uma representação binária de um caractere Unicode para qualquer uma de suas representações binárias equivalentes. A normalização pode usar vários algoritmos, chamados de formulários de normalização, que seguem regras diferentes. O .NET oferece suporte aos formulários de normalização Unicode C, D, KC e KD. Quando as cadeias de caracteres foram normalizadas para a mesma forma de normalização, elas podem ser comparadas usando a comparação ordinal.
Uma comparação ordinal é uma comparação binária do valor escalar Unicode dos objetos correspondentes Char em cada cadeia de caracteres. A String classe inclui vários métodos que podem executar uma comparação ordinal, incluindo o seguinte:
Qualquer sobrecarga dos Comparemétodos , , , EndsWithIndexOf, EqualsStartsWithe LastIndexOf que inclui um StringComparison parâmetro. O método executa uma comparação ordinal se você fornecer um valor de StringComparison.Ordinal ou OrdinalIgnoreCase para esse parâmetro.
As sobrecargas do CompareOrdinal método.
Métodos que usam comparação ordinal por padrão, como Contains, Replacee Split.
Métodos que procuram um Char valor ou os elementos em uma matriz em uma Char instância de cadeia de caracteres. Tais métodos incluem IndexOf(Char) e Split(Char[]).
Você pode determinar se uma cadeia de caracteres é normalizada para o formulário de normalização C chamando o método ou você pode chamar o String.IsNormalized()String.IsNormalized(NormalizationForm) método para determinar se uma cadeia de caracteres é normalizada para um formulário de normalização especificado. Você também pode chamar o método para converter uma cadeia de caracteres em forma de normalização C ou pode chamar o String.Normalize()String.Normalize(NormalizationForm) método para converter uma cadeia de caracteres em um formulário de normalização especificado. Para obter informações passo a passo sobre como normalizar e comparar cadeias de caracteres, consulte os Normalize() métodos e Normalize(NormalizationForm) .
O exemplo simples a seguir ilustra a normalização de cadeia de caracteres. Ele define a letra "ố" de três maneiras diferentes em três cadeias de caracteres diferentes, e usa uma comparação ordinal para igualdade para determinar que cada cadeia de caracteres difere das outras duas cadeias de caracteres. Em seguida, ele converte cada cadeia de caracteres para os formulários de normalização com suporte e novamente executa uma comparação ordinal de cada cadeia de caracteres em um formulário de normalização especificado. Em cada caso, o segundo teste de igualdade mostra que as cadeias de caracteres são iguais.
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
Para obter mais informações sobre formulários de normalização e normalização, consulte System.Text.NormalizationForm, bem como Unicode Standard Annex #15: Unicode Normalization Forms e as Perguntas frequentes sobre normalização no site da unicode.org.
Operações da cadeia de caracteres por categoria
A String classe fornece membros para comparar cadeias de caracteres, testar cadeias de caracteres para igualdade, localizar caracteres ou subcadeias de caracteres em uma cadeia de caracteres, modificar uma cadeia de caracteres, extrair subcadeias de caracteres de uma cadeia de caracteres, combinar cadeias de caracteres, formatar valores, copiar uma cadeia de caracteres e normalizar uma cadeia de caracteres.
Comparar cadeias de caracteres
Você pode comparar cadeias de caracteres para determinar sua posição relativa na ordem de classificação usando os seguintes String métodos:
Compare Retorna um inteiro que indica a relação de uma cadeia de caracteres com uma segunda cadeia de caracteres na ordem de classificação.
CompareOrdinal Retorna um inteiro que indica a relação de uma cadeia de caracteres para uma segunda cadeia de caracteres com base em uma comparação de seus pontos de código.
CompareTo Retorna um inteiro que indica a relação da instância de cadeia de caracteres atual com uma segunda cadeia de caracteres na ordem de classificação. O CompareTo(String) método fornece o IComparable e IComparable<T> implementações para a String classe.
Testar a igualdade das cadeias de caracteres
Você chama o Equals método para determinar se duas cadeias de caracteres são iguais. A instância Equals(String, String, StringComparison) e as sobrecargas estáticas Equals(String, StringComparison) permitem especificar se a comparação é sensível à cultura ou ordinal e se as maiúsculas e minúsculas são consideradas ou ignoradas. A maioria dos testes de igualdade é ordinal, e as comparações para igualdade que determinam o acesso a um recurso do sistema (como um objeto do sistema de arquivos) devem ser sempre ordinais.
Localizar caracteres em uma cadeia de caracteres
A String classe inclui dois tipos de métodos de pesquisa:
Métodos que retornam um Boolean valor para indicar se uma subcadeia de caracteres específica está presente em uma instância de cadeia de caracteres. Estes incluem o Contains, EndsWithe StartsWith métodos.
Métodos que indicam a posição inicial de uma substring em uma ocorrência de string. Estes incluem o IndexOf, , , IndexOfAnyLastIndexOfe LastIndexOfAny métodos.
Aviso
Se você quiser pesquisar uma cadeia de caracteres para um padrão específico em vez de uma subcadeia de caracteres específica, você deve usar expressões regulares. Para obter mais informações, consulte Expressões regulares do .NET.
Modificar uma cadeia de caracteres
A String classe inclui os seguintes métodos que parecem modificar o valor de uma cadeia de caracteres:
Insert Insere uma cadeia de caracteres na instância atual String .
PadLeft Insere uma ou mais ocorrências de um caractere especificado no início de uma cadeia de caracteres.
PadRight Insere uma ou mais ocorrências de um caractere especificado no final de uma cadeia de caracteres.
Replace Substitui uma substring por outra substring na instância atual String .
ToLower e converta ToLowerInvariant todos os caracteres em uma cadeia de caracteres em minúsculas.
ToUpper e converta ToUpperInvariant todos os caracteres em uma cadeia de caracteres em maiúsculas.
Trim Remove todas as ocorrências de um caractere do início e do fim de uma cadeia de caracteres.
TrimEnd Remove todas as ocorrências de um caractere do final de uma cadeia de caracteres.
TrimStart Remove todas as ocorrências de um caractere do início de uma cadeia de caracteres.
Importante
Todos os métodos de modificação de cadeia de caracteres retornam um novo String objeto. Eles não modificam o valor da instância atual.
Extrair substrings de uma cadeia de caracteres
O String.Split método separa uma única cadeia de caracteres em várias cadeias de caracteres. As sobrecargas do método permitem especificar vários delimitadores, limitar o número de subcadeias de caracteres que o método extrai, cortar espaço em branco de subcadeias de caracteres e especificar se cadeias de caracteres vazias (que ocorrem quando os delimitadores são adjacentes) são incluídas entre as cadeias de caracteres retornadas.
Combinar cadeias de caracteres
Os seguintes String métodos podem ser usados para concatenação de cadeia de caracteres:
- Concat Combina uma ou mais subcadeias de caracteres em uma única cadeia de caracteres.
- Join Concatena uma ou mais subcadeias de caracteres em um único elemento e adiciona um separador entre cada subcadeia de caracteres.
Formatar valores
O String.Format método usa o recurso de formatação composta para substituir um ou mais espaços reservados em uma cadeia de caracteres com a representação de cadeia de caracteres de algum objeto ou valor. O Format método é frequentemente usado para fazer o seguinte:
- Para incorporar a representação de cadeia de caracteres de um valor numérico em uma cadeia de caracteres.
- Para incorporar a representação de cadeia de caracteres de um valor de data e hora em uma cadeia de caracteres.
- Para incorporar a representação de cadeia de caracteres de um valor de enumeração em uma cadeia de caracteres.
- Para incorporar a representação de cadeia de caracteres de algum objeto que ofereça suporte à IFormattable interface em uma cadeia de caracteres.
- Para justificar à direita ou à esquerda uma subcadeia de caracteres em um campo dentro de uma cadeia de caracteres maior.
Para obter informações detalhadas sobre operações de formatação e exemplos, consulte o resumo de Format sobrecarga.
Copiar uma cadeia de caracteres
Você pode chamar os seguintes String métodos para fazer uma cópia de uma cadeia de caracteres:
- Clone Retorna uma referência a um objeto existente String .
- Copy Cria uma cópia de uma cadeia de caracteres existente.
- CopyTo Copia uma parte de uma cadeia de caracteres para uma matriz de caracteres.
Normalizar uma cadeia de caracteres
Em Unicode, um único caractere pode ter vários pontos de código. A normalização converte esses caracteres equivalentes na mesma representação binária. O String.Normalize método executa a normalização e o String.IsNormalized método determina se uma cadeia de caracteres é normalizada.
Para obter mais informações e um exemplo, consulte a seção Normalização anteriormente neste artigo.
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de