Codifica dei caratteri in .NETCharacter encoding in .NET

Questo articolo offre un'introduzione ai sistemi di codifica degli char acter usati da .NET.This article provides an introduction to character encoding systems that are used by .NET. L'articolo illustra il funzionamento dei tipi String , , e con Char Rune StringInfo Unicode, UTF-16 e UTF-8.The article explains how the String, Char, Rune, and StringInfo types work with Unicode, UTF-16, and UTF-8.

Il termine char acter viene usato in questo caso nel senso generale di ciò che un lettore considera come un singolo elemento di visualizzazione.The term character is used here in the general sense of what a reader perceives as a single display element. Esempi comuni sono la lettera "a", il simbolo "@" e l'emoji " 🐂 ".Common examples are the letter "a", the symbol "@", and the emoji "🐂". A volte ciò che sembra un agire è in realtà costituito da più elementi di visualizzazione indipendenti, come illustrato nella sezione sui char cluster grapheme.Sometimes what looks like one character is actually composed of multiple independent display elements, as the section on grapheme clusters explains.

Tipi string char eThe string and char types

Un'istanza della string classe rappresenta del testo.An instance of the string class represents some text. Un oggetto è logicamente una sequenza di valori a 16 bit, ognuno dei quali string è un'istanza dello char struct .A string is logically a sequence of 16-bit values, each of which is an instance of the char struct. Oggetto string . La proprietà Length restituisce il numero char di istanze string nell'istanza.The string.Length property returns the number of char instances in the string instance.

La funzione di esempio seguente stampa i valori in notazione esadecimale di tutte le char istanze in un oggetto string :The following sample function prints out the values in hexadecimal notation of all the char instances in a string:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/PrintStringChars.cs" id="SnippetPrintChars"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/PrintStringChars.cs" id="SnippetPrintChars":::

Passare string "Hello" a questa funzione per ottenere l'output seguente:Pass the string "Hello" to this function, and you get the following output:

PrintChars("Hello");
"Hello".Length = 5
s[0] = 'H' ('\u0048')
s[1] = 'e' ('\u0065')
s[2] = 'l' ('\u006c')
s[3] = 'l' ('\u006c')
s[4] = 'o' ('\u006f')

Ogni char acter è rappresentato da un singolo char valore.Each character is represented by a single char value. Questo modello è valido per la maggior parte delle lingue del mondo.That pattern holds true for most of the world's languages. Ad esempio, di seguito è riportato l'output per due acter cinesi che nǐ hǎo char e significano Hello: For example, here's the output for two Chinese characters that sound like nǐ hǎo and mean Hello:

PrintChars("你好");
"你好".Length = 2
s[0] = '你' ('\u4f60')
s[1] = '好' ('\u597d')

Tuttavia, per alcune lingue e per alcuni simboli ed emoji, sono necessari due char istanze per rappresentare un singolo char acter.However, for some languages and for some symbols and emoji, it takes two char instances to represent a single character. Ad esempio, confrontare gli acter e le istanze nella parola che significa char char Osage nella lingua di Osage:For example, compare the characters and char instances in the word that means Osage in the Osage language:

PrintChars("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟");
"𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟".Length = 17
s[0] = '�' ('\ud801')
s[1] = '�' ('\udccf')
s[2] = '�' ('\ud801')
s[3] = '�' ('\udcd8')
s[4] = '�' ('\ud801')
s[5] = '�' ('\udcfb')
s[6] = '�' ('\ud801')
s[7] = '�' ('\udcd8')
s[8] = '�' ('\ud801')
s[9] = '�' ('\udcfb')
s[10] = '�' ('\ud801')
s[11] = '�' ('\udcdf')
s[12] = ' ' ('\u0020')
s[13] = '�' ('\ud801')
s[14] = '�' ('\udcbb')
s[15] = '�' ('\ud801')
s[16] = '�' ('\udcdf')

Nell'esempio precedente, ogni char acter ad eccezione dello spazio è rappresentato da due char istanze .In the preceding example, each character except the space is represented by two char instances.

Una singola emoji Unicode è rappresentata anche da due, come illustrato char nell'esempio seguente che mostra un emoji di bue:A single Unicode emoji is also represented by two chars, as seen in the following example showing an ox emoji:

"🐂".Length = 2
s[0] = '�' ('\ud83d')
s[1] = '�' ('\udc02')

Questi esempi mostrano che il valore di , che indica il numero di istanze, non indica necessariamente il string.Length char numero di char acter visualizzati.These examples show that the value of string.Length, which indicates the number of char instances, doesn't necessarily indicate the number of displayed characters. Una singola char istanza di per sé non rappresenta necessariamente un char acter.A single char instance by itself doesn't necessarily represent a character.

Le char coppie mappate a un singolo char acter sono denominate coppie di surrogati.The char pairs that map to a single character are called surrogate pairs. Per comprendere il funzionamento, è necessario comprendere la codifica Unicode e UTF-16.To understand how they work, you need to understand Unicode and UTF-16 encoding.

Punti di codice UnicodeUnicode code points

Unicode è uno standard di codifica internazionale da usare in varie piattaforme e con diversi linguaggi e script.Unicode is an international encoding standard for use on various platforms and with various languages and scripts.

Lo standard Unicode definisce oltre 1,1 milioni di punti di codice.The Unicode Standard defines over 1.1 million code points. Un punto di codice è un valore intero che può essere compreso tra 0 e U+10FFFF (decimale 1.114.111).A code point is an integer value that can range from 0 to U+10FFFF (decimal 1,114,111). Alcuni punti di codice vengono assegnati a lettere, simboli o emoji.Some code points are assigned to letters, symbols, or emoji. Altri vengono assegnati ad azioni che controllano la modalità di visualizzazione del testo o degli acter, ad esempio char l'avanzamento a una nuova riga.Others are assigned to actions that control how text or characters are displayed, such as advance to a new line. Molti punti di codice non sono ancora assegnati.Many code points are not yet assigned.

Ecco alcuni esempi di assegnazioni di punti di codice, con collegamenti a char t Unicode in cui vengono visualizzati:Here are some examples of code point assignments, with links to Unicode charts in which they appear:

DecimalDecimal HexHex EsempioExample DescrizioneDescription
1010 U+000A N/DN/A AVANZAMENTO RIGALINE FEED
9797 U+0061 aa LETTERA MINUSCOLA LATINO ALATIN SMALL LETTER A
562562 U+0232 ȲȲ LETTERA MAIUSCOLA IN ALFABETO LATINO Y CON MACRONLATIN CAPITAL LETTER Y WITH MACRON
68,67568,675 U+10C43 𐱃𐱃 VECCHIA LETTERA TURCA ORKHON ATOLD TURKIC LETTER ORKHON AT
127,801127,801 U+1F339 🌹🌹 EMOJI ROSEROSE emoji

I punti di codice vengono definiti in modo personalizzato usando la sintassi U+xxxx , dove è il valore intero con codifica xxxx esadecimale.Code points are customarily referred to by using the syntax U+xxxx, where xxxx is the hex-encoded integer value.

All'interno dell'intera gamma di punti di codice sono presenti due intervalli secondari:Within the full range of code points there are two subranges:

  • Piano BMP (Basic Multilingual Plane) nell'intervallo U+0000..U+FFFF .The Basic Multilingual Plane (BMP) in the range U+0000..U+FFFF. Questo intervallo a 16 bit fornisce 65.536 punti di codice, sufficienti per coprire la maggior parte dei sistemi di scrittura del mondo.This 16-bit range provides 65,536 code points, enough to cover the majority of the world's writing systems.
  • Punti di codice supplementari nell'intervallo U+10000..U+10FFFF .Supplementary code points in the range U+10000..U+10FFFF. Questo intervallo a 21 bit offre più di un milione di punti di codice aggiuntivi che possono essere usati per linguaggi meno noti e altri scopi, ad esempio emoji.This 21-bit range provides more than a million additional code points that can be used for less well-known languages and other purposes such as emojis.

Il diagramma seguente illustra la relazione tra il BMP e i punti di codice supplementari.The following diagram illustrates the relationship between the BMP and the supplementary code points.

BMP and supplementary code points

Unità di codice UTF-16UTF-16 code units

Il formato di trasformazione Unicode a 16 bit (UTF-16) è un sistema di codifica acter che usa unità di codice a 16 bit per rappresentare i char punti di codice Unicode. 16-bit Unicode Transformation Format (UTF-16) is a character encoding system that uses 16-bit code units to represent Unicode code points. .NET usa UTF-16 per codificare il testo in un oggetto string ..NET uses UTF-16 to encode the text in a string. charUn'istanza di rappresenta un'unità di codice a 16 bit.A char instance represents a 16-bit code unit.

Una singola unità di codice a 16 bit può rappresentare qualsiasi punto di codice nell'intervallo a 16 bit del piano multilingue di base.A single 16-bit code unit can represent any code point in the 16-bit range of the Basic Multilingual Plane. Tuttavia, per un punto di codice nell'intervallo supplementare, sono char necessarie due istanze .But for a code point in the supplementary range, two char instances are needed.

Coppie di surrogatiSurrogate pairs

La conversione di due valori a 16 bit in un singolo valore a 21 bit è facilitata da un intervallo speciale denominato punti di codice surrogato, da a U+D800 U+DFFF (decimale 55.296 a 57.343), inclusi.The translation of two 16-bit values to a single 21-bit value is facilitated by a special range called the surrogate code points, from U+D800 to U+DFFF (decimal 55,296 to 57,343), inclusive.

Il diagramma seguente illustra la relazione tra il BMP e i punti di codice surrogati.The following diagram illustrates the relationship between the BMP and the surrogate code points.

BMP and surrogate code points

Quando un punto di codice surrogato elevato ( ) è immediatamente seguito da un punto di codice surrogato basso ( ), la coppia viene interpretata come punto di codice supplementare usando U+D800..U+DBFF la formula U+DC00..U+DFFF seguente:When a high surrogate code point (U+D800..U+DBFF) is immediately followed by a low surrogate code point (U+DC00..U+DFFF), the pair is interpreted as a supplementary code point by using the following formula:

code point = 0x10000 +
  ((high surrogate code point - 0xD800) * 0x0400) +
  (low surrogate code point - 0xDC00)

Ecco la stessa formula che usa la notazione decimale:Here's the same formula using decimal notation:

code point = 65,536 +
  ((high surrogate code point - 55,296) * 1,024) +
  (low surrogate code point - 56,320)

Un punto di codice surrogato alto non ha un valore numerico superiore rispetto a un punto di codice surrogato basso.A high surrogate code point doesn't have a higher number value than a low surrogate code point. Il punto di codice surrogato alto viene chiamato "high" perché viene usato per calcolare gli 11 bit di ordine superiore dell'intervallo completo dei punti di codice a 21 bit.The high surrogate code point is called "high" because it's used to calculate the higher-order 11 bits of the full 21-bit code point range. Il punto di codice surrogato basso viene usato per calcolare i 10 bit di ordine inferiore.The low surrogate code point is used to calculate the lower-order 10 bits.

Ad esempio, il punto di codice effettivo che corrisponde alla coppia di surrogati 0xD83C e viene calcolato come 0xDF39 segue:For example, the actual code point that corresponds to the surrogate pair 0xD83C and 0xDF39 is computed as follows:

actual = 0x10000 + ((0xD83C - 0xD800) * 0x0400) + (0xDF39 - 0xDC00)
       = 0x10000 + (          0x003C  * 0x0400) +           0x0339
       = 0x10000 +                      0xF000  +           0x0339
       = 0x1F339

Ecco lo stesso calcolo usando la notazione decimale:Here's the same calculation using decimal notation:

actual =  65,536 + ((55,356 - 55,296) * 1,024) + (57,145 - 56320)
       =  65,536 + (              60  * 1,024) +             825
       =  65,536 +                     61,440  +             825
       = 127,801

Nell'esempio precedente viene "\ud83c\udf39" illustrata la codifica UTF-16 del punto U+1F339 ROSE ('🌹') di codice indicato in precedenza.The preceding example demonstrates that "\ud83c\udf39" is the UTF-16 encoding of the U+1F339 ROSE ('🌹') code point mentioned earlier.

Valori scalari UnicodeUnicode scalar values

Il termine valore scalare Unicode fa riferimento a tutti i punti di codice diversi da quelli surrogati.The term Unicode scalar value refers to all code points other than the surrogate code points. In altre parole, un valore scalare è qualsiasi punto di codice a cui è assegnato un acter o a cui può essere assegnato char char un acter in futuro.In other words, a scalar value is any code point that is assigned a character or can be assigned a character in the future. "Carattere" qui si riferisce a qualsiasi elemento che può essere assegnato a un punto di codice, che include elementi quali azioni che controllano la modalità di visualizzazione del testo o char degli acter."Character" here refers to anything that can be assigned to a code point, which includes such things as actions that control how text or characters are displayed.

Il diagramma seguente illustra i punti di codice del valore scalare.The following diagram illustrates the scalar value code points.

Valori scalari

Tipo Rune come valore scalareThe Rune type as a scalar value

A partire da .NET Core 3.0, il System.Text.Rune tipo rappresenta un valore scalare Unicode.Beginning with .NET Core 3.0, the System.Text.Rune type represents a Unicode scalar value. Rune non è disponibile in .NET Core 2.x o .NET Framework 4.x.Rune is not available in .NET Core 2.x or .NET Framework 4.x.

I Rune costruttori convalidano che l'istanza risultante è un valore scalare Unicode valido, in caso contrario generano un'eccezione.The Rune constructors validate that the resulting instance is a valid Unicode scalar value, otherwise they throw an exception. L'esempio seguente illustra il codice che crea correttamente istanze Rune di perché l'input rappresenta valori scalari validi:The following example shows code that successfully instantiates Rune instances because the input represents valid scalar values:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/Instantiate Rune s.cs" id="SnippetValid"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/InstantiateRunes.cs" id="SnippetValid":::

L'esempio seguente genera un'eccezione perché il punto di codice è compreso nell'intervallo di surrogati e non fa parte di una coppia di surrogati:The following example throws an exception because the code point is in the surrogate range and isn't part of a surrogate pair:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/Instantiate Rune s.cs" id="SnippetInvalidSurrogate"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/InstantiateRunes.cs" id="SnippetInvalidSurrogate":::

L'esempio seguente genera un'eccezione perché il punto di codice non è compreso nell'intervallo supplementare:The following example throws an exception because the code point is beyond the supplementary range:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/Instantiate Rune s.cs" id="SnippetInvalidHigh"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/InstantiateRunes.cs" id="SnippetInvalidHigh":::

Rune Esempio di utilizzo: modifica della lettera maiuscola/minuscolaRune usage example: changing letter case

Un'API che accetta e presuppone che funzioni con un punto di codice che è un valore scalare non funziona correttamente se è da una char char coppia di surrogati.An API that takes a char and assumes it is working with a code point that is a scalar value doesn't work correctly if the char is from a surrogate pair. Si consideri ad esempio il metodo seguente che chiama Char.ToUpperInvariant su ogni in un oggetto char string :For example, consider the following method that calls Char.ToUpperInvariant on each char in a string:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/ConvertToUpper.cs" id="SnippetBadExample"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/ConvertToUpper.cs" id="SnippetBadExample":::

Se contiene input string la lettera minuscola di Deseret ( ), questo codice non la er 𐑉 convertirà in maiuscolo ( 𐐡 ).If the input string contains the lowercase Deseret letter er (𐑉), this code won't convert it to uppercase (𐐡). Il codice chiama char.ToUpperInvariant separatamente su ogni punto di codice surrogato, U+D801 e U+DC49 .The code calls char.ToUpperInvariant separately on each surrogate code point, U+D801 and U+DC49. Ma non dispone di informazioni sufficienti per identificarla come lettera U+D801 minuscola, quindi char.ToUpperInvariant lasciarla da sola.But U+D801 doesn't have enough information by itself to identify it as a lowercase letter, so char.ToUpperInvariant leaves it alone. E gestisce U+DC49 allo stesso modo.And it handles U+DC49 the same way. Il risultato è che la lettera minuscola "𐑉" in non viene convertita in input string "𐐡" maiuscola.The result is that lowercase '𐑉' in the input string doesn't get converted to uppercase '𐐡'.

Di seguito sono disponibili due opzioni per la corretta conversione di string un oggetto in maiuscolo:Here are two options for correctly converting a string to uppercase:

  • Chiamare String.ToUpperInvariant sull'input string anziché iterare char -by-. charCall String.ToUpperInvariant on the input string rather than iterating char-by-char. Il string.ToUpperInvariant metodo ha accesso a entrambe le parti di ogni coppia di surrogati, in modo da poter gestire correttamente tutti i punti di codice Unicode.The string.ToUpperInvariant method has access to both parts of each surrogate pair, so it can handle all Unicode code points correctly.

  • Scorrere i valori scalari Unicode come istanze anziché come istanze Rune char , come illustrato nell'esempio seguente.Iterate through the Unicode scalar values as Rune instances instead of char instances, as shown in the following example. Poiché un'istanza è un valore scalare Unicode valido, può essere passata alle API che prevedono di Rune operare su un valore scalare.Since a Rune instance is a valid Unicode scalar value, it can be passed to APIs that expect to operate on a scalar value. Ad esempio, la Rune.ToUpperInvariant chiamata di come illustrato nell'esempio seguente restituisce risultati corretti:For example, calling Rune.ToUpperInvariant as shown in the following example gives correct results:

    :::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/ConvertToUpper.cs" id="SnippetGoodExample"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/ConvertToUpper.cs" id="SnippetGoodExample":::

Altre Rune APIOther Rune APIs

Il Rune tipo espone gli analoghi di molte char API.The Rune type exposes analogs of many of the char APIs. Ad esempio, i metodi seguenti rispecchiano le API statiche nel char tipo :For example, the following methods mirror static APIs on the char type:

Per ottenere il valore scalare non elaborato da Rune un'istanza di , usare la Rune.Value proprietà .To get the raw scalar value from a Rune instance, use the Rune.Value property.

Per convertire di Rune nuovo un'istanza in una sequenza di char , usare o il metodo Rune.ToString Rune.EncodeToUtf16 .To convert a Rune instance back to a sequence of chars, use Rune.ToString or the Rune.EncodeToUtf16 method.

Poiché qualsiasi valore scalare Unicode è rappresentabile da una singola o da una coppia di surrogati, qualsiasi istanza può essere rappresentata da char Rune al massimo 2 char istanze.Since any Unicode scalar value is representable by a single char or by a surrogate pair, any Rune instance can be represented by at most 2 char instances. Usare Rune.Utf16SequenceLength per visualizzare il numero di istanze necessarie per rappresentare char Rune un'istanza.Use Rune.Utf16SequenceLength to see how many char instances are required to represent a Rune instance.

Per altre informazioni sul tipo Rune .NET, vedere le informazioni di riferimento sulle Rune API.For more information about the .NET Rune type, see the Rune API reference.

Cluster graphemeGrapheme clusters

Ciò che sembra un acter potrebbe derivare da una combinazione di più punti di codice, quindi un termine più descrittivo che viene spesso usato al posto di char char "acter" è grapheme cluster.What looks like one character might result from a combination of multiple code points, so a more descriptive term that is often used in place of "character" is grapheme cluster. Il termine equivalente in .NET è l'elemento di testo.The equivalent term in .NET is text element.

Si string considerino le istanze "a", "á", "á" e " 👩🏽‍🚒 ".Consider the string instances "a", "á", "á", and "👩🏽‍🚒". Se il sistema operativo li gestisce come specificato dallo standard Unicode, ognuna di queste istanze viene visualizzata come singolo elemento di testo string o cluster di grafiemi.If your operating system handles them as specified by the Unicode standard, each of these string instances appears as a single text element or grapheme cluster. Ma gli ultimi due sono rappresentati da più di un punto di codice con valori scalari.But the last two are represented by more than one scalar value code point.

  • La string "a" è rappresentata da un valore scalare e contiene char un'istanza.The string "a" is represented by one scalar value and contains one char instance.

    • U+0061 LATIN SMALL LETTER A
  • string"á" è rappresentato da un valore scalare e contiene un'istanza. charThe string "á" is represented by one scalar value and contains one char instance.

    • U+00E1 LATIN SMALL LETTER A WITH ACUTE
  • "á" ha lo stesso aspetto string di "á", ma è rappresentato da due valori scalari e contiene due char istanze.The string "á" looks the same as "á" but is represented by two scalar values and contains two char instances.

    • U+0061 LATIN SMALL LETTER A
    • U+0301 COMBINING ACUTE ACCENT
  • Infine, string " 👩🏽‍🚒 " è rappresentato da quattro valori scalari e contiene sette char istanze.Finally, the string "👩🏽‍🚒" is represented by four scalar values and contains seven char instances.

    • U+1F469 WOMAN (intervallo supplementare, richiede una coppia di surrogati)U+1F469 WOMAN (supplementary range, requires a surrogate pair)
    • U+1F3FD EMOJI MODIFIER FITZPATRICK TYPE-4 (intervallo supplementare, richiede una coppia di surrogati)U+1F3FD EMOJI MODIFIER FITZPATRICK TYPE-4 (supplementary range, requires a surrogate pair)
    • U+200D ZERO WIDTH JOINER
    • U+1F692 FIRE ENGINE (intervallo supplementare, richiede una coppia di surrogati)U+1F692 FIRE ENGINE (supplementary range, requires a surrogate pair)

In alcuni degli esempi precedenti, ad esempio il modificatore di combinazione degli accenti o del tono dell'interfaccia, il punto di codice non viene visualizzato sullo schermo come elemento autonomo.In some of the preceding examples - such as the combining accent modifier or the skin tone modifier - the code point does not display as a standalone element on the screen. Serve invece a modificare l'aspetto di un elemento di testo che è stato prima di esso.Rather, it serves to modify the appearance of a text element that came before it. Questi esempi mostrano che potrebbero essere stati utilizzati più valori scalari per creare ciò che si pensa come un singolo char "acter" o "cluster grapheme".These examples show that it might take multiple scalar values to make up what we think of as a single "character," or "grapheme cluster."

Per enumerare i cluster grapheme di string un oggetto , usare la classe come illustrato StringInfo nell'esempio seguente.To enumerate the grapheme clusters of a string, use the StringInfo class as shown in the following example. Se si ha familiarità con Swift, il tipo .NET StringInfo è concettualmente simile al tipo character di Swift.If you're familiar with Swift, the .NET StringInfo type is conceptually similar to Swift's character type.

Esempio: istanze di elementi di testo , e char Rune countExample: count char, Rune, and text element instances

Nelle API .NET un cluster grapheme è denominato elemento di testo.In .NET APIs, a grapheme cluster is called a text element. Il metodo seguente illustra le differenze tra char le istanze degli elementi di testo , e in un oggetto Rune string :The following method demonstrates the differences between char, Rune, and text element instances in a string:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/CountTextElements.cs" id="SnippetCountMethod"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/CountTextElements.cs" id="SnippetCountMethod":::

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/CountTextElements.cs" id="SnippetCallCountMethod"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/CountTextElements.cs" id="SnippetCallCountMethod":::

Se si esegue questo codice in .NET Framework o .NET Core 3.1 o versioni precedenti, il conteggio degli elementi di testo per l'emoji mostra 4 .If you run this code in .NET Framework or .NET Core 3.1 or earlier, the text element count for the emoji shows 4. Ciò è dovuto a un bug nella StringInfo classe risolto in .NET 5.That is due to a bug in the StringInfo class that is fixed in .NET 5.

Esempio: suddivisione di string istanzeExample: splitting string instances

Quando si string sudondono le istanze, evitare di suddividere coppie di surrogati e cluster grapheme.When splitting string instances, avoid splitting surrogate pairs and grapheme clusters. Si consideri l'esempio seguente di codice non corretto, che prevede l'inserimento di interruzioni di riga ogni 10 char acter in string un oggetto :Consider the following example of incorrect code, which intends to insert line breaks every 10 characters in a string:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/InsertNewlines.cs" id="SnippetBadExample"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/InsertNewlines.cs" id="SnippetBadExample":::

Poiché questo codice enumera le istanze, una coppia di surrogati che si verifica a un confine di 10 caratteri verrà suddivisa e tra di esse verrà inserita char char una nuova riga.Because this code enumerates char instances, a surrogate pair that happens to straddle a 10-char boundary will be split and a newline injected between them. Questo inserimento introduce il danneggiamento dei dati, perché i punti di codice surrogati sono significativi solo come coppie.This insertion introduces data corruption, because surrogate code points are meaningful only as pairs.

Il rischio di danneggiamento dei dati non viene eliminato se si enumerano Rune le istanze (valori scalari) anziché le char istanze.The potential for data corruption isn't eliminated if you enumerate Rune instances (scalar values) instead of char instances. Un set di istanze può creare un cluster di grafiemi che si Rune snoda su un limite di 10. charA set of Rune instances might make up a grapheme cluster that straddles a 10-char boundary. Se il set di cluster grapheme è suddiviso, non può essere interpretato correttamente.If the grapheme cluster set is split up, it can't be interpreted correctly.

Un approccio migliore consiste nell'interrompere il conteggio dei cluster di grafiemi, o elementi di string testo, come nell'esempio seguente:A better approach is to break the string by counting grapheme clusters, or text elements, as in the following example:

:::code language="csharp" source="snippets/ char acter-encoding-introduction/csharp/InsertNewlines.cs" id="SnippetGoodExample"::::::code language="csharp" source="snippets/character-encoding-introduction/csharp/InsertNewlines.cs" id="SnippetGoodExample":::

Come illustrato in precedenza, tuttavia, nelle implementazioni di .NET diverse da .NET 5, la classe potrebbe gestire in modo non corretto alcuni StringInfo cluster grapheme.As noted earlier, however, in implementations of .NET other than .NET 5, the StringInfo class might handle some grapheme clusters incorrectly.

UTF-8 e UTF-32UTF-8 and UTF-32

Le sezioni precedenti sono incentrate su UTF-16 perché questo è ciò che .NET usa per codificare le string istanze.The preceding sections focused on UTF-16 because that's what .NET uses to encode string instances. Esistono altri sistemi di codifica per Unicode - UTF-8 e UTF-32.There are other encoding systems for Unicode - UTF-8 and UTF-32. Queste codifiche usano rispettivamente unità di codice a 8 bit e unità di codice a 32 bit.These encodings use 8-bit code units and 32-bit code units, respectively.

Analogamente a UTF-16, UTF-8 richiede più unità di codice per rappresentare alcuni valori scalari Unicode.Like UTF-16, UTF-8 requires multiple code units to represent some Unicode scalar values. UTF-32 può rappresentare qualsiasi valore scalare in una singola unità di codice a 32 bit.UTF-32 can represent any scalar value in a single 32-bit code unit.

Ecco alcuni esempi che illustrano come viene rappresentato lo stesso punto di codice Unicode in ognuno di questi tre sistemi di codifica Unicode:Here are some examples showing how the same Unicode code point is represented in each of these three Unicode encoding systems:

Scalar: U+0061 LATIN SMALL LETTER A ('a')
UTF-8 : [ 61 ]           (1x  8-bit code unit  = 8 bits total)
UTF-16: [ 0061 ]         (1x 16-bit code unit  = 16 bits total)
UTF-32: [ 00000061 ]     (1x 32-bit code unit  = 32 bits total)

Scalar: U+0429 CYRILLIC CAPITAL LETTER SHCHA ('Щ')
UTF-8 : [ D0 A9 ]        (2x  8-bit code units = 16 bits total)
UTF-16: [ 0429 ]         (1x 16-bit code unit  = 16 bits total)
UTF-32: [ 00000429 ]     (1x 32-bit code unit  = 32 bits total)

Scalar: U+A992 JAVANESE LETTER GA ('ꦒ')
UTF-8 : [ EA A6 92 ]     (3x  8-bit code units = 24 bits total)
UTF-16: [ A992 ]         (1x 16-bit code unit  = 16 bits total)
UTF-32: [ 0000A992 ]     (1x 32-bit code unit  = 32 bits total)

Scalar: U+104CC OSAGE CAPITAL LETTER TSHA ('𐓌')
UTF-8 : [ F0 90 93 8C ]  (4x  8-bit code units = 32 bits total)
UTF-16: [ D801 DCCC ]    (2x 16-bit code units = 32 bits total)
UTF-32: [ 000104CC ]     (1x 32-bit code unit  = 32 bits total)

Come illustrato in precedenza, una singola unità di codice UTF-16 di una coppia di surrogati non ha alcun significato.As noted earlier, a single UTF-16 code unit from a surrogate pair is meaningless by itself. Allo stesso modo, una singola unità di codice UTF-8 non ha alcun significato se si trova in una sequenza di due, tre o quattro usati per calcolare un valore scalare.In the same way, a single UTF-8 code unit is meaningless by itself if it's in a sequence of two, three, or four used to calculate a scalar value.

Ordine dei byteEndianness

In .NET le unità di codice UTF-16 di un oggetto vengono archiviate in memoria contigua come sequenza di interi string a 16 bit ( char istanze ).In .NET, the UTF-16 code units of a string are stored in contiguous memory as a sequence of 16-bit integers (char instances). I bit delle singole unità di codice sono disposti in base all'endianness dell'architettura corrente.The bits of individual code units are laid out according to the endianness of the current architecture.

In un'architettura little-endian, l'oggetto costituito dai punti di codice string UTF-16 viene definito in memoria come byte [ D801 DCCC ] [ 0x01, 0xD8, 0xCC, 0xDC ] .On a little-endian architecture, the string consisting of the UTF-16 code points [ D801 DCCC ] would be laid out in memory as the bytes [ 0x01, 0xD8, 0xCC, 0xDC ]. In un'architettura big-endian che verrebbe disposti in memoria come string byte [ 0xD8, 0x01, 0xDC, 0xCC ] .On a big-endian architecture that same string would be laid out in memory as the bytes [ 0xD8, 0x01, 0xDC, 0xCC ].

I sistemi informatici che comunicano tra loro devono concordare sulla rappresentazione dei dati in transito.Computer systems that communicate with each other must agree on the representation of data crossing the wire. La maggior parte dei protocolli di rete usa UTF-8 come standard per la trasmissione di testo, in parte per evitare problemi che potrebbero derivare da un computer big endian che comunica con un computer little-endian.Most network protocols use UTF-8 as a standard when transmitting text, partly to avoid issues that might result from a big-endian machine communicating with a little-endian machine. stringL'oggetto costituito dai punti di codice UTF-8 verrà sempre rappresentato come byte [ F0 90 93 8C ] [ 0xF0, 0x90, 0x93, 0x8C ] indipendentemente dall'endianness.The string consisting of the UTF-8 code points [ F0 90 93 8C ] will always be represented as the bytes [ 0xF0, 0x90, 0x93, 0x8C ] regardless of endianness.

Per usare UTF-8 per la trasmissione di testo, le applicazioni .NET usano spesso codice simile all'esempio seguente:To use UTF-8 for transmitting text, .NET applications often use code like the following example:

string stringToWrite = GetString();
byte[] stringAsUtf8Bytes = Encoding.UTF8.GetBytes(stringToWrite);
await outputStream.WriteAsync(stringAsUtf8Bytes, 0, stringAsUtf8Bytes.Length);

Nell'esempio precedente il metodo Encoding.UTF8.GetBytes decodifica la codifica UTF-16 in una serie di valori scalari Unicode, quindi ricodifica tali valori scalari in UTF-8 e inserisce la sequenza risultante in string una byte matrice.In the preceding example, the method Encoding.UTF8.GetBytes decodes the UTF-16 string back into a series of Unicode scalar values, then it re-encodes those scalar values into UTF-8 and places the resulting sequence into a byte array. Il metodo Encoding.UTF8.GetString esegue la trasformazione opposta, convertendo una matrice UTF-8 byte in utf-16. stringThe method Encoding.UTF8.GetString performs the opposite transformation, converting a UTF-8 byte array to a UTF-16 string.

Avviso

Poiché UTF-8 è comune in Internet, può essere allettante leggere byte non elaborati dalla rete e trattare i dati come se fossero UTF-8.Since UTF-8 is commonplace on the internet, it may be tempting to read raw bytes from the wire and to treat the data as if it were UTF-8. È tuttavia necessario verificare che il formato sia corretto.However, you should validate that it is indeed well-formed. Un client dannoso potrebbe inviare utf-8 in formato non corretto al servizio.A malicious client might submit ill-formed UTF-8 to your service. Se si opera su questi dati come se fossero ben formati, potrebbero verificarsi errori o problemi di sicurezza nell'applicazione.If you operate on that data as if it were well-formed, it could cause errors or security holes in your application. Per convalidare i dati UTF-8, è possibile usare un metodo come , che eseguirà la convalida durante la conversione dei dati Encoding.UTF8.GetString in ingresso in string .To validate UTF-8 data, you can use a method like Encoding.UTF8.GetString, which will perform validation while converting the incoming data to a string.

Codifica ben formataWell-formed encoding

Una codifica Unicode ben formata è un di unità di codice che possono essere decodificate senza ambiguità e senza errori in una sequenza di string valori scalari Unicode.A well-formed Unicode encoding is a string of code units that can be decoded unambiguously and without error into a sequence of Unicode scalar values. I dati ben formati possono essere transcodificati liberamente tra UTF-8, UTF-16 e UTF-32.Well-formed data can be transcoded freely back and forth between UTF-8, UTF-16, and UTF-32.

La domanda se una sequenza di codifica è ben formata o meno non è correlata all'ordine dei caratteri dell'architettura di un computer.The question of whether an encoding sequence is well-formed or not is unrelated to the endianness of a machine's architecture. Una sequenza UTF-8 in formato non corretto non è valida nello stesso modo nei computer big-endian e little-endian.An ill-formed UTF-8 sequence is ill-formed in the same way on both big-endian and little-endian machines.

Ecco alcuni esempi di codifiche in formato non corretto:Here are some examples of ill-formed encodings:

  • In UTF-8 la sequenza non [ 6C C2 61 ] è in formato corretto perché non può essere seguita da C2 61 .In UTF-8, the sequence [ 6C C2 61 ] is ill-formed because C2 cannot be followed by 61.

  • In UTF-16 la sequenza (o, in C#, ) non è corretta perché il surrogato basso non può essere seguito da un altro [ DC00 DD00 ] string "\udc00\udd00" DC00 surrogato DD00 basso.In UTF-16, the sequence [ DC00 DD00 ] (or, in C#, the string "\udc00\udd00") is ill-formed because the low surrogate DC00 cannot be followed by another low surrogate DD00.

  • In UTF-32 la sequenza non è in formato corretto perché non rientra [ 0011ABCD ] 0011ABCD nell'intervallo di valori scalari Unicode.In UTF-32, the sequence [ 0011ABCD ] is ill-formed because 0011ABCD is outside the range of Unicode scalar values.

In .NET le string istanze contengono quasi sempre dati UTF-16 ben formati, ma questo non è garantito.In .NET, string instances almost always contain well-formed UTF-16 data, but that isn't guaranteed. Gli esempi seguenti illustrano codice C# valido che crea dati UTF-16 in formato non corretto nelle string istanze di .The following examples show valid C# code that creates ill-formed UTF-16 data in string instances.

  • Valore letterale non valido:An ill-formed literal:

    const string s = "\ud800";
    
  • Sotto che string suddivide una coppia di surrogati:A substring that splits up a surrogate pair:

    string x = "\ud83e\udd70"; // "🥰"
    string y = x.Substring(1, 1); // "\udd70" standalone low surrogate
    

Le API come non Encoding.UTF8.GetString restituiscono mai istanze in formato string non corretto.APIs like Encoding.UTF8.GetString never return ill-formed string instances. Encoding.GetString I metodi e rilevano sequenze in Encoding.GetBytes formato non corretto nell'input ed eseguono char la sostituzione dell'acter durante la generazione dell'output.Encoding.GetString and Encoding.GetBytes methods detect ill-formed sequences in the input and perform character substitution when generating the output. Ad esempio, se viene visualizzato un byte non ASCII nell'input (non compreso nell'intervallo Encoding.ASCII.GetString(byte[]) U+0000..U+007F), inserisce un '?' nell'istanza string restituita.For example, if Encoding.ASCII.GetString(byte[]) sees a non-ASCII byte in the input (outside the range U+0000..U+007F), it inserts a '?' into the returned string instance. Encoding.UTF8.GetString(byte[]) sostituisce sequenze UTF-8 in formato non corretto con U+FFFD REPLACEMENT CHARACTER ('�') nell'istanza string restituita.Encoding.UTF8.GetString(byte[]) replaces ill-formed UTF-8 sequences with U+FFFD REPLACEMENT CHARACTER ('�') in the returned string instance. Per altre informazioni, vedere Unicode Standard, Sezioni 5.22 e 3.9.For more information, see the Unicode Standard, Sections 5.22 and 3.9.

Le classi incorporate possono anche essere configurate per generare un'eccezione anziché eseguire la sostituzione dell'acter quando vengono viste sequenze Encoding char in formato non corretto.The built-in Encoding classes can also be configured to throw an exception rather than perform character substitution when ill-formed sequences are seen. Questo approccio viene spesso usato nelle applicazioni sensibili alla sicurezza in cui la char sostituzione dell'acter potrebbe non essere accettabile.This approach is often used in security-sensitive applications where character substitution might not be acceptable.

byte[] utf8Bytes = ReadFromNetwork();
UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
string asString = encoding.GetString(utf8Bytes); // will throw if 'utf8Bytes' is ill-formed

Per informazioni su come usare le classi incorporate, vedere Come usare le classi Encoding di codifica char acter in .NET.For information about how to use the built-in Encoding classes, see How to use character encoding classes in .NET.

Vedi ancheSee also