Come convertire UTF-8 byte [] in stringa?


932

Ho un byte[]array che viene caricato da un file che mi capita di conoscere contiene UTF-8 .

In alcuni codici di debug, devo convertirli in una stringa. C'è una fodera che lo farà?

Sotto le coperte dovrebbe essere solo un'allocazione e una memcopia , quindi anche se non è implementato, dovrebbe essere possibile.


5
"dovrebbe essere solo un'allocazione e una memcopia": non è corretto perché una stringa .NET è codificata UTF-16. Un carattere Unicode può essere un'unità di codice UTF-8 o un'unità di codice UTF-16. un'altra potrebbe essere due unità di codice UTF-8 o un'unità di codice UTF-16, un'altra potrebbe essere tre unità di codice UTF-8 o un'unità di codice UTF-16, un'altra potrebbe essere quattro unità di codice UTF-8 o due unità di codice UTF-16 . Una memcopia potrebbe essere in grado di allargarsi ma non sarebbe in grado di gestire la conversione da UTF-8 a UTF-16.
Tom Blodget,

Risposte:


1470
string result = System.Text.Encoding.UTF8.GetString(byteArray);

13
come gestisce le stringhe nulle?
Maazza,

14
@maazza per motivi sconosciuti non lo è affatto. Lo sto chiamando come System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
Hi-Angel,

15
@ Hi-Angel Motivo sconosciuto? L'unico motivo per cui le stringhe con terminazione null sono mai diventate popolari era il linguaggio C - e anche quello era solo a causa di una stranezza storica (istruzioni della CPU che si occupavano delle stringhe con terminazione null). .NET utilizza stringhe con terminazione null solo quando si interrompe con il codice che utilizza stringhe con terminazione null (che infine stanno scomparendo). È perfettamente valido per una stringa contenere caratteri NUL. E ovviamente, mentre le stringhe con terminazione null sono assolutamente semplici in ASCII (basta costruire fino a quando non si ottiene il primo byte zero), altre codifiche, incluso UTF-8, non sono così semplici.
Luaan,

4
Una delle belle caratteristiche di UTF-8 è che una sequenza più breve non è mai una sottosequenza di una sequenza più lunga. Quindi una stringa UTF-8 con terminazione null è semplice.
lavare il

10
Bene, buona fortuna disimballarlo se ha non ascii. Basta usare Convert.ToBase64String.
Erik Bergstedt,

323

Esistono almeno quattro modi diversi per eseguire questa conversione.

  1. GetString della codifica
    , ma non sarai in grado di recuperare i byte originali se quei byte hanno caratteri non ASCII.

  2. BitConverter.ToString
    L'output è una stringa delimitata da "-", ma non esiste un metodo incorporato .NET per riconvertire la stringa in array di byte.

  3. Convert.ToBase64String
    È possibile convertire facilmente la stringa di output in array di byte utilizzando Convert.FromBase64String.
    Nota: la stringa di output potrebbe contenere '+', '/' e '='. Se si desidera utilizzare la stringa in un URL, è necessario codificarla esplicitamente.

  4. HttpServerUtility.UrlTokenEncode
    È possibile riconvertire facilmente la stringa di output in array di byte utilizzando HttpServerUtility.UrlTokenDecode. La stringa di output è già compatibile con l'URL! Il rovescio della medaglia è che ha bisogno di essere System.Webassemblato se il tuo progetto non è un progetto web.

Un esempio completo:

byte[] bytes = { 130, 200, 234, 23 }; // A byte array contains non-ASCII (or non-readable) characters

string s1 = Encoding.UTF8.GetString(bytes); // ���
byte[] decBytes1 = Encoding.UTF8.GetBytes(s1);  // decBytes1.Length == 10 !!
// decBytes1 not same as bytes
// Using UTF-8 or other Encoding object will get similar results

string s2 = BitConverter.ToString(bytes);   // 82-C8-EA-17
String[] tempAry = s2.Split('-');
byte[] decBytes2 = new byte[tempAry.Length];
for (int i = 0; i < tempAry.Length; i++)
    decBytes2[i] = Convert.ToByte(tempAry[i], 16);
// decBytes2 same as bytes

string s3 = Convert.ToBase64String(bytes);  // gsjqFw==
byte[] decByte3 = Convert.FromBase64String(s3);
// decByte3 same as bytes

string s4 = HttpServerUtility.UrlTokenEncode(bytes);    // gsjqFw2
byte[] decBytes4 = HttpServerUtility.UrlTokenDecode(s4);
// decBytes4 same as bytes

7
LINQ:var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
drtf,

25

Una soluzione generale per convertire da array di byte a stringa quando non si conosce la codifica:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}

3
Ma questo presuppone che ci sia una distinta base di codifica nel flusso di byte o che sia in UTF-8. Ma puoi fare lo stesso con la codifica comunque. Non risolve magicamente il problema quando non si conosce la codifica.
Sebastian Zander,

12

Definizione:

public static string ConvertByteToString(this byte[] source)
{
    return source != null ? System.Text.Encoding.UTF8.GetString(source) : null;
}

usando:

string result = input.ConvertByteToString();

9

La conversione di a byte[]in stringsembra semplice ma è probabile che qualsiasi tipo di codifica incasini la stringa di output. Questa piccola funzione funziona senza risultati imprevisti:

private string ToString(byte[] bytes)
{
    string response = string.Empty;

    foreach (byte b in bytes)
        response += (Char)b;

    return response;
}

Ho ricevuto System.FormatException usando il tuo metodo quando l'ho decompresso con Convert.FromBase64String.
Erik Bergstedt,

@ AndrewJE questo richiederà anche per il calcolo se si dispone di un array di byte di grandi dimensioni come quello utilizzato dalle immagini.
user3841581

7

Usando (byte)b.ToString("x2"), Usciteb4b5dfe475e58b67

public static class Ext {

    public static string ToHexString(this byte[] hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return string.Empty;

        var s = new StringBuilder();
        foreach (byte b in hex) {
            s.Append(b.ToString("x2"));
        }
        return s.ToString();
    }

    public static byte[] ToHexBytes(this string hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return new byte[0];

        int l = hex.Length / 2;
        var b = new byte[l];
        for (int i = 0; i < l; ++i) {
            b[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return b;
    }

    public static bool EqualsTo(this byte[] bytes, byte[] bytesToCompare)
    {
        if (bytes == null && bytesToCompare == null) return true; // ?
        if (bytes == null || bytesToCompare == null) return false;
        if (object.ReferenceEquals(bytes, bytesToCompare)) return true;

        if (bytes.Length != bytesToCompare.Length) return false;

        for (int i = 0; i < bytes.Length; ++i) {
            if (bytes[i] != bytesToCompare[i]) return false;
        }
        return true;
    }

}

4

Esiste anche la classe UnicodeEncoding, abbastanza semplice nell'uso:

ByteConverter = new UnicodeEncoding();
string stringDataForEncoding = "My Secret Data!";
byte[] dataEncoded = ByteConverter.GetBytes(stringDataForEncoding);

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));

Ma non i methink UTF-8?
david.pfx,

1
UnicodeEncodingè il peggior nome di classe in assoluto; unicode non è affatto una codifica. Quella classe è in realtà UTF-16. La versione little-endian, penso.
Nyerguds,

3

In alternativa:

 var byteStr = Convert.ToBase64String(bytes);

2

Un one-liner Linq per convertire un array di byte byteArrFilenameletto da un file in una stringa a terminazione zero in puro stile C ascii sarebbe questo: Comodo per leggere cose come tabelle di indice di file in vecchi formati di archivio.

String filename = new String(byteArrFilename.TakeWhile(x => x != 0)
                              .Select(x => x < 128 ? (Char)x : '?').ToArray());

Uso qui '?'il carattere predefinito per tutto ciò che non è puro ASCII, ma che può essere modificato, ovviamente. Se vuoi essere sicuro di poterlo rilevare, usa '\0'invece, poiché TakeWhileall'inizio assicura che una stringa costruita in questo modo non possa contenere '\0'valori dalla sorgente di input.


2

BitConverterLa classe può essere utilizzata per convertire un byte[]in string.

var convertedString = BitConverter.ToString(byteAttay);

La documentazione di BitConverterclasse può essere fonte su MSDN


1
Ciò converte l'array di byte in una stringa esadecimale che rappresenta ciascun byte, che generalmente non è quello che si desidera quando si convertono byte in una stringa. Se lo fai, allora questa è un'altra domanda, vedi ad esempio Come si converte la matrice di byte in stringa esadecimale e viceversa? .
CodeCaster

Non è quello che OP ha chiesto
Inverno

2

Per quanto ne so, nessuna delle risposte fornite garantisce un comportamento corretto con una risoluzione nulla. Finché qualcuno non mi mostra diversamente ho scritto la mia classe statica per gestirla con i seguenti metodi:

// Mimics the functionality of strlen() in c/c++
// Needed because niether StringBuilder or Encoding.*.GetString() handle \0 well
static int StringLength(byte[] buffer, int startIndex = 0)
{
    int strlen = 0;
    while
    (
        (startIndex + strlen + 1) < buffer.Length // Make sure incrementing won't break any bounds
        && buffer[startIndex + strlen] != 0       // The typical null terimation check
    )
    {
        ++strlen;
    }
    return strlen;
}

// This is messy, but I haven't found a built-in way in c# that guarentees null termination
public static string ParseBytes(byte[] buffer, out int strlen, int startIndex = 0)
{
    strlen = StringLength(buffer, startIndex);
    byte[] c_str = new byte[strlen];
    Array.Copy(buffer, startIndex, c_str, 0, strlen);
    return Encoding.UTF8.GetString(c_str);
}

Il motivo per cui startIndexstava nell'esempio su cui stavo lavorando in particolare avevo bisogno di analizzare byte[]un array di stringhe con terminazione null. Può essere tranquillamente ignorato nel caso semplice


Il mio lo fa, in realtà. byteArr.TakeWhile(x => x != 0)è un modo semplice e veloce per risolvere il problema di risoluzione null.
Nyerguds,

1

hier è un risultato in cui non devi preoccuparti della codifica. L'ho usato nella mia classe di rete e ho inviato oggetti binari come stringa con esso.

        public static byte[] String2ByteArray(string str)
        {
            char[] chars = str.ToArray();
            byte[] bytes = new byte[chars.Length * 2];

            for (int i = 0; i < chars.Length; i++)
                Array.Copy(BitConverter.GetBytes(chars[i]), 0, bytes, i * 2, 2);

            return bytes;
        }

        public static string ByteArray2String(byte[] bytes)
        {
            char[] chars = new char[bytes.Length / 2];

            for (int i = 0; i < chars.Length; i++)
                chars[i] = BitConverter.ToChar(bytes, i * 2);

            return new string(chars);
        }

non ne avevo uno. Ma questa funzione è utilizzata per la trasmissione binaria nella nostra rete aziendale e finora 20 TB sono stati ricodificati e codificati correttamente. Quindi per me questa funzione funziona :)
Marco Pardo,

1

In aggiunta alla risposta selezionata, se si utilizza .NET35 o .NET35 CE, è necessario specificare l'indice del primo byte da decodificare e il numero di byte da decodificare:

string result = System.Text.Encoding.UTF8.GetString(byteArray,0,byteArray.Length);

0

Prova questa app console:

static void Main(string[] args)
{
    //Encoding _UTF8 = Encoding.UTF8;
    string[] _mainString = { "Héllo World" };
    Console.WriteLine("Main String: " + _mainString);

    //Convert a string to utf-8 bytes.
    byte[] _utf8Bytes = Encoding.UTF8.GetBytes(_mainString[0]);

    //Convert utf-8 bytes to a string.
    string _stringuUnicode = Encoding.UTF8.GetString(_utf8Bytes);
    Console.WriteLine("String Unicode: " + _stringuUnicode);
}

0

Ho visto alcune risposte in questo post ed è possibile essere considerato conoscenza di base completa, perché hanno diversi approcci nella programmazione C # per risolvere lo stesso problema. Solo una cosa che deve essere presa in considerazione riguarda una differenza tra Pure UTF-8 e UTF-8 con BOM .

Nell'ultima settimana, nel mio lavoro, ho bisogno di sviluppare una funzionalità che produca file CSV con BOM e altri CSV con UTF-8 puro (senza BOM), ogni tipo di codifica di file CSV sarà utilizzato da diverse API non standardizzate, quella L'API legge UTF-8 con BOM e l'altra API viene letta senza BOM. Ho bisogno di ricercare i riferimenti su questo concetto, leggendo " Qual è la differenza tra UTF-8 e UTF-8 senza BOM? " Discussione Stack Overflow e questo link di Wikipedia " Contrassegno di byte " per costruire il mio approccio.

Infine, la mia programmazione C # per entrambi i tipi di codifica UTF-8 (con BOM e pure) doveva essere simile come nell'esempio seguente:

//for UTF-8 with B.O.M., equals shared by Zanoni (at top)
string result = System.Text.Encoding.UTF8.GetString(byteArray);

//for Pure UTF-8 (without B.O.M.)
string result = (new UTF8Encoding(false)).GetString(byteArray);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.