c# - utf8 - vb net utf 8 encoding




Come ottengo una rappresentazione di byte coerente di stringhe in C#senza specificare manualmente una codifica? (20)

Come posso convertire una string in un byte[] in .NET (C #) senza specificare manualmente una codifica specifica?

Ho intenzione di crittografare la stringa. Posso crittografarlo senza convertirli, ma mi piacerebbe ancora sapere perché la codifica viene qui a giocare.

Inoltre, perché la codifica dovrebbe essere presa in considerazione? Non posso semplicemente ottenere in quale byte è stata memorizzata la stringa? Perché c'è una dipendenza dalle codifiche dei caratteri?


Spiega anche perché la codifica deve essere presa in considerazione. Non posso semplicemente ottenere in quale byte è stata memorizzata la stringa? Perché questa dipendenza dalla codifica? !!!

Perché non esistono cose come "i byte della stringa".

Una stringa (o più genericamente, un testo) è composta da caratteri: lettere, cifre e altri simboli. È tutto. I computer, tuttavia, non sanno nulla dei personaggi; possono gestire solo byte. Pertanto, se si desidera archiviare o trasmettere il testo utilizzando un computer, è necessario trasformare i caratteri in byte. Come si fa a farlo? Ecco dove arrivano le codifiche sulla scena.

Una codifica non è altro che una convenzione per tradurre i caratteri logici in byte fisici. La codifica più semplice e più conosciuta è ASCII, ed è tutto ciò che serve se scrivi in ​​inglese. Per altre lingue avrete bisogno di codifiche più complete, essendo uno dei sapori Unicode la scelta più sicura al giorno d'oggi.

Quindi, in breve, cercare di "ottenere i byte di una stringa senza utilizzare le codifiche" è impossibile quanto "scrivere un testo senza usare alcun linguaggio".

A proposito, ti consiglio vivamente (e chiunque altro) di leggere questo piccolo pezzo di saggezza: joelonsoftware.com/articles/Unicode.html


Come posso convertire una stringa in un byte [] in .NET (C #) senza specificare manualmente una codifica specifica?

Una string in .NET rappresenta il testo come una sequenza di unità di codice UTF-16, quindi i byte sono già codificati in memoria in UTF-16.

La risposta di Mehrdad

Puoi usare la risposta di Mehrdad , ma in realtà usa una codifica perché i caratteri sono UTF-16. Chiama ToCharArray che guardando la sorgente crea char[]e copia direttamente la memoria su di essa. Quindi copia i dati in un array di byte che viene anche allocato. Quindi sotto il cofano sta copiando i byte sottostanti due volte e allocando un array di caratteri che non viene utilizzato dopo la chiamata.

La risposta di Tom Blodget

La risposta di Tom Blodget è del 20-30% più veloce di Mehrdad poiché salta il passaggio intermedio dell'allocazione di un array di caratteri e copia i byte su di esso, ma richiede la compilazione con l' /unsafeopzione. Se non vuoi assolutamente usare la codifica, penso che questa sia la strada da percorrere. Se si inserisce il login di crittografia all'interno del fixedblocco, non è nemmeno necessario allocare un array di byte separato e copiare i byte su di esso.

Inoltre, perché la codifica dovrebbe essere presa in considerazione? Non posso semplicemente ottenere in quale byte è stata memorizzata la stringa? Perché c'è una dipendenza dalle codifiche dei caratteri?

Perché quello è il modo giusto per farlo. stringè un'astrazione.

L'utilizzo di una codifica potrebbe causare problemi se si dispone di "stringhe" con caratteri non validi, ma ciò non dovrebbe accadere. Se stai ricevendo dati nella tua stringa con caratteri non validi, stai sbagliando. Probabilmente dovresti usare una matrice di byte o una codifica Base64 per iniziare.

Se lo usi System.Text.Encoding.Unicode, il tuo codice sarà più resistente. Non devi preoccuparti della endianness del sistema su cui verrà eseguito il tuo codice. Non è necessario preoccuparsi se la versione successiva di CLR utilizzerà una codifica di caratteri interna diversa.

Penso che la domanda non sia perché vuoi preoccuparti della codifica, ma perché vuoi ignorarla e usare qualcos'altro. La codifica è intesa per rappresentare l'astrazione di una stringa in una sequenza di byte. System.Text.Encoding.Unicodeti fornirà una piccola codifica per l'ordine dei byte endian e eseguirà lo stesso su ogni sistema, ora e in futuro.


Contrariamente alle risposte qui, NON è necessario preoccuparsi della codifica se i byte non devono essere interpretati!

Come hai detto, il tuo obiettivo è, semplicemente, "ottenere in quale byte è stata memorizzata la stringa" .
(E, naturalmente, per essere in grado di ricostruire la stringa dai byte.)

Per quegli obiettivi, onestamente non capisco perché la gente continui a dirti che hai bisogno delle codifiche. Sicuramente non devi preoccuparti delle codifiche per questo.

Basta fare questo invece:

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

Finché il tuo programma (o altri programmi) non tenta di interpretare i byte in qualche modo, cosa che ovviamente non hai menzionato tu intendi fare, allora non c'è niente di sbagliato in questo approccio! Preoccuparsi delle codifiche ti rende la vita più complicata senza una vera ragione.

Ulteriori vantaggi per questo approccio:

Non importa se la stringa contiene caratteri non validi, perché puoi comunque ottenere i dati e ricostruire comunque la stringa originale!

Sarà codificato e decodificato allo stesso modo, perché stai solo guardando i byte .

Se hai usato una codifica specifica, però, ti avrebbe dato problemi con la codifica / decodifica di caratteri non validi.


È necessario prendere in considerazione la codifica, poiché 1 carattere può essere rappresentato da 1 o più byte (fino a circa 6) e le codifiche differenti gestiranno questi byte in modo diverso.

Joel ha un post su questo:

joelonsoftware.com/articles/Unicode.html


Dipende dalla codifica della stringa ( ASCII , UTF-8 , ...).

Per esempio:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

Un piccolo esempio per cui la codifica è importante:

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII semplicemente non è equipaggiato per trattare personaggi speciali.

Internamente, il framework .NET utilizza UTF-16 per rappresentare le stringhe, quindi se si desidera semplicemente ottenere i byte esatti utilizzati da .NET, utilizzare System.Text.Encoding.Unicode.GetBytes (...) .

Vedere Codifica caratteri in .NET Framework (MSDN) per ulteriori informazioni.


La prima parte della tua domanda (come ottenere i byte) ha già ricevuto risposta da altri: guarda nello spazio dei nomi System.Text.Encoding .

Tratterò la tua domanda di follow-up: perché hai bisogno di scegliere una codifica? Perché non puoi ottenerlo dalla stessa classe di stringhe?

La risposta è in due parti.

Prima di tutto, i byte usati internamente dalla classe string non hanno importanza , e ogni volta che si presume lo facciano probabilmente introducendo un bug.

Se il tuo programma è interamente all'interno del mondo .Net, allora non devi preoccuparti di ottenere array di byte per le stringhe, anche se stai inviando dati attraverso una rete. Invece, utilizzare la serializzazione .Net per preoccuparsi della trasmissione dei dati. Non ti preoccupare più dei byte effettivi: il formattatore di serializzazione lo fa per te.

D'altra parte, cosa succede se si inviano questi byte da qualche parte che non si può garantire l'estrazione dei dati da un flusso serializzato .Net? In questo caso hai sicuramente bisogno di preoccuparti della codifica, perché ovviamente questo sistema esterno si preoccupa. Quindi, di nuovo, i byte interni utilizzati dalla stringa non contano: è necessario scegliere una codifica in modo da poter essere espliciti su questa codifica sul lato ricevente, anche se è la stessa codifica utilizzata internamente da .Net.

Capisco che in questo caso potresti preferire utilizzare i byte effettivi memorizzati dalla variabile stringa nella memoria, ove possibile, con l'idea che potrebbe salvare del lavoro creando il flusso di byte. Tuttavia, l'ho messo per te non è importante rispetto al fare in modo che il tuo output sia compreso dall'altra parte, e per garantire che tu debba essere esplicito con la tua codifica. Inoltre, se vuoi davvero abbinare i tuoi byte interni, puoi già scegliere la codifica Unicode e ottenere così un risparmio di prestazioni.

Il che mi porta alla seconda parte ... la scelta della codifica Unicode sta dicendo a .Net di usare i byte sottostanti. È necessario scegliere questa codifica, perché quando esce Unicode-Plus un po 'nuovo, il runtime .Net deve essere libero di utilizzare questo modello di codifica più recente e migliore senza interrompere il programma. Ma, per il momento (e il futuro prevedibile), scegliere la codifica Unicode ti dà quello che vuoi.

È anche importante capire che la stringa deve essere riscritta sul filo, e ciò implica almeno una certa traduzione del pattern di bit anche quando si utilizza una codifica corrispondente . Il computer deve tenere conto di cose come Big vs Little Endian, ordine dei byte di rete, pacchetti, informazioni sulla sessione, ecc.


Prova questo, molto meno codice:

System.Text.Encoding.UTF8.GetBytes("TEST String");

Questa è una domanda popolare. È importante capire che cosa chiede la domanda all'autore e che è diversa da quella che è probabilmente la necessità più comune. Per scoraggiare l'uso improprio del codice laddove non è necessario, ho risposto per primo.

Bisogno comune

Ogni stringa ha un set di caratteri e codifica. Quando converti un oggetto System.String in un array di System.Byte hai ancora un set di caratteri e una codifica. Per la maggior parte degli usi, sapresti quale set di caratteri e codifica hai bisogno e .NET semplifica la "copia con conversione". Basta scegliere la classe di Encoding appropriata.

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

La conversione potrebbe dover gestire casi in cui il set di caratteri di destinazione o la codifica non supportano un carattere presente nella fonte. Avete alcune scelte: eccezione, sostituzione o salto. La politica di default è di sostituire un '?'.

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

Chiaramente, le conversioni non sono necessariamente senza perdite!

Nota: per System.String il set di caratteri di origine è Unicode.

L'unica cosa confusa è che .NET usa il nome di un set di caratteri per il nome di una particolare codifica di quel set di caratteri. Encoding.Unicode dovrebbe essere chiamato Encoding.UTF16 .

Questo è tutto per la maggior parte degli usi. Se è quello di cui hai bisogno, smetti di leggere qui. Guarda il divertente joelonsoftware.com/articles/Unicode.html se non capisci cos'è una codifica.

Bisogno specifico

Ora, la domanda dell'autore chiede: "Ogni stringa è memorizzata come una matrice di byte, giusto? Perché non posso semplicemente avere quei byte?"

Lui non vuole alcuna conversione.

Dalla specifica C # :

L'elaborazione di caratteri e stringhe in C # utilizza la codifica Unicode. Il tipo di carattere rappresenta un'unità di codice UTF-16 e il tipo di stringa rappresenta una sequenza di unità di codice UTF-16.

Quindi, sappiamo che se chiediamo la conversione null (cioè da UTF-16 a UTF-16), otterremo il risultato desiderato:

Encoding.Unicode.GetBytes(".NET String to byte array")

Ma per evitare la menzione delle codifiche, dobbiamo farlo in un altro modo. Se un tipo di dati intermedi è accettabile, esiste una scorciatoia concettuale per questo:

".NET String to byte array".ToCharArray()

Questo non ci porta il tipo di dati desiderato, ma la risposta di Mehrdad mostra come convertire questo array Char in un array Byte usando BlockCopy . Tuttavia, questo copia la stringa due volte! Inoltre, utilizza esplicitamente un codice specifico per la codifica: il tipo di dati System.Char .

L'unico modo per ottenere i byte effettivi in ​​cui è memorizzata la stringa è utilizzare un puntatore. L'istruzione fixed consente di prendere l'indirizzo dei valori. Dalla specifica C #:

[For] un'espressione di tipo stringa, ... l'inizializzatore calcola l'indirizzo del primo carattere nella stringa.

Per fare ciò, il compilatore scrive il codice salta sulle altre parti dell'oggetto stringa con RuntimeHelpers.OffsetToStringData . Quindi, per ottenere i byte non elaborati, basta creare un puntatore alla stringa e copiare il numero di byte necessari.

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

Come sottolineato da @CodesInChaos, il risultato dipende dalla endianità della macchina. Ma l'autore della domanda non si occupa di questo.


Uso:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

Il risultato è:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103

È possibile utilizzare il seguente codice per la conversione tra array di stringhe e byte.

string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);

codice semplice con LINQ

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT: come commentato di seguito, non è un buon modo.

ma puoi ancora usarlo per capire LINQ con una codifica più appropriata:

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();

Basta usare questo:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);

È possibile utilizzare il seguente codice per convertire stringin a byte arrayin .NET

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);

C # per convertire stringun bytearray in un array:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}

Ecco il mio pericoloso attuazione Stringalla Byte[]conversione:

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

È molto più veloce di quella accettata, anche se non è elegante come è. Ecco i miei benchmark di cronometro su oltre 10000000 iterazioni:

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

Per utilizzarlo, devi spuntare "Consenti codice non sicuro" nelle proprietà di costruzione del tuo progetto. Secondo .NET Framework 3.5, questo metodo può essere utilizzato anche come estensione String:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}

Il problema chiave è che un glifo in una stringa accetta 32 bit (16 bit per un codice carattere) ma un byte ha solo 8 bit da risparmiare. Una mappatura uno-a-uno non esiste se non ti limiti alle stringhe che contengono solo caratteri ASCII. System.Text.Encoding ha molti modi per mappare una stringa in byte [], devi sceglierne una che eviti la perdita di informazioni e che sia facile da usare dal tuo client quando deve mappare il byte [] su una stringa .

Utf8 è una codifica popolare, è compatta e non lossy.


La stringa può essere convertita in array di byte in diversi modi, a causa del fatto seguente: .NET supporta Unicode e Unicode standardizza diverse codifiche di differenze chiamate UTF. Hanno una lunghezza diversa di rappresentazione in byte ma sono equivalenti in questo senso quando una stringa viene codificata, può essere codificata nuovamente nella stringa, ma se la stringa è codificata con una UTF e decodificata nell'ipotesi di UTF differente se può essere avvitata su.

Inoltre, .NET supporta codifiche non Unicode, ma non sono valide in generale (sarà valido solo se un sottoinsieme limitato di punto di codice Unicode viene utilizzato in una stringa effettiva, come ASCII). Internamente, .NET supporta UTF-16, ma per la rappresentazione del flusso, UTF-8 viene solitamente utilizzato. È anche uno standard di fatto per Internet.

Non sorprende che la serializzazione della stringa in una matrice di byte e deserializzazione sia supportata dalla classe System.Text.Encoding, che è una classe astratta; le sue classi derivate supportano codifiche concrete: ASCIIEncodinge quattro UTF ( System.Text.UnicodeEncodingsupporta UTF-16)

Rifiuta questo link.

Per la serializzazione su una matrice di byte usando System.Text.Encoding.GetBytes. Per l'operazione inversa utilizzare System.Text.Encoding.GetChars. Questa funzione restituisce una matrice di caratteri, quindi per ottenere una stringa, utilizzare un costruttore di stringhe System.String(char[]).
Ref questa pagina.

Esempio:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)

Non sono sicuro, ma penso che la stringa memorizzi le sue informazioni come una serie di caratteri, che è inefficiente con i byte. Nello specifico, la definizione di Char è "Rappresenta un carattere Unicode".

prendi questo esempio di esempio:

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

Prendi nota che la risposta Unicode è 14 byte in entrambe le istanze, mentre la risposta UTF-8 è solo 9 byte per la prima e solo 7 per la seconda.

Quindi, se si desidera solo i byte utilizzati dalla stringa, è sufficiente utilizzarli Encoding.Unicode, ma sarà inefficiente con lo spazio di archiviazione.


BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}




character-encoding