Comment convertir l'octet UTF-8 [] en chaîne?


932

J'ai un byte[]tableau qui est chargé à partir d'un fichier que je connais contient UTF-8 .

Dans un code de débogage, j'ai besoin de le convertir en chaîne. Y a-t-il une doublure qui fera cela?

Sous les couvertures, il ne devrait y avoir qu'une allocation et une copie , donc même si elle n'est pas implémentée, cela devrait être possible.


5
"devrait être juste une allocation et une copie mémoire": n'est pas correct car une chaîne .NET est encodée en UTF-16. Un caractère Unicode peut être une unité de code UTF-8 ou une unité de code UTF-16. un autre peut être deux unités de code UTF-8 ou une unité de code UTF-16, un autre peut être trois unités de code UTF-8 ou une unité de code UTF-16, un autre peut être quatre unités de code UTF-8 ou deux unités de code UTF-16 . Une memcopy pourrait être en mesure de s'élargir mais elle ne pourrait pas gérer la conversion UTF-8 en UTF-16.
Tom Blodget

Réponses:


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

13
comment gère-t-il les chaînes nulles?
maazza

14
@maazza pour une raison inconnue, ce n'est pas du tout le cas. Je l'appelle comme System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
Hi-Angel

15
@ Hi-Angel Raison inconnue? La seule raison pour laquelle les chaînes à terminaison nulle sont devenues populaires était le langage C - et même cela n'était dû qu'à une bizarrerie historique (instructions du processeur traitant des chaînes à terminaison nulle). .NET utilise uniquement des chaînes terminées par null lors de l'interopérabilité avec du code qui utilise des chaînes terminées par null (qui disparaissent finalement ). Il est parfaitement valable qu'une chaîne contienne des caractères NUL. Et bien sûr, alors que les chaînes terminées par null sont simples en ASCII (il suffit de les construire jusqu'à ce que vous obteniez le premier octet zéro), d'autres encodages, y compris UTF-8, ne sont pas aussi simples.
Luaan

4
L'une des belles caractéristiques de l'UTF-8 est qu'une séquence plus courte n'est jamais une sous-séquence d'une séquence plus longue. Ainsi, une chaîne UTF-8 terminée par null est simple.
plugwash du

10
Eh bien, bonne chance pour le déballer s'il n'a pas d'ascii. Utilisez simplement Convert.ToBase64String.
Erik Bergstedt du

323

Il existe au moins quatre façons différentes d'effectuer cette conversion.

  1. GetString de l'encodage
    , mais vous ne pourrez pas récupérer les octets d'origine si ces octets ont des caractères non ASCII.

  2. BitConverter.ToString
    La sortie est une chaîne délimitée par "-", mais il n'y a pas de méthode intégrée .NET pour reconvertir la chaîne en tableau d'octets.

  3. Convert.ToBase64String
    Vous pouvez facilement reconvertir la chaîne de sortie en tableau d'octets à l'aide de Convert.FromBase64String.
    Remarque: la chaîne de sortie peut contenir «+», «/» et «=». Si vous souhaitez utiliser la chaîne dans une URL, vous devez la coder explicitement.

  4. HttpServerUtility.UrlTokenEncode
    Vous pouvez facilement reconvertir la chaîne de sortie en tableau d'octets à l'aide de HttpServerUtility.UrlTokenDecode. La chaîne de sortie est déjà compatible avec les URL! L'inconvénient est qu'il doit être System.Webassemblé si votre projet n'est pas un projet Web.

Un exemple complet:

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 it:var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
drtf

25

Une solution générale pour convertir un tableau d'octets en chaîne lorsque vous ne connaissez pas l'encodage:

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

3
Mais cela suppose qu'il existe soit une nomenclature de codage dans le flux d'octets, soit qu'elle est en UTF-8. Mais vous pouvez tout de même faire de même avec l'encodage. Cela ne résout pas comme par magie le problème lorsque vous ne connaissez pas l'encodage.
Sebastian Zander

12

Définition:

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

En utilisant:

string result = input.ConvertByteToString();

9

La conversion de a byte[]en a stringsemble simple mais tout type d'encodage risque de gâcher la chaîne de sortie. Cette petite fonction fonctionne simplement sans résultats inattendus:

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

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

    return response;
}

J'ai reçu System.FormatException en utilisant votre méthode lorsque je l'ai décompressée avec Convert.FromBase64String.
Erik Bergstedt

@ AndrewJE, cela prendra même pour calculer si vous avez un grand tableau d'octets comme celui utilisé dans les images.
user3841581

7

Utilisation (byte)b.ToString("x2"), sortiesb4b5dfe475e58b67

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

Il existe également la classe UnicodeEncoding, assez simple à utiliser:

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

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

Mais pas les méthinkes UTF-8?
david.pfx

1
UnicodeEncodingest le pire nom de classe jamais; unicode n'est pas du tout un encodage. Cette classe est en fait UTF-16. La version little-endian, je pense.
Nyerguds

3

Alternativement:

 var byteStr = Convert.ToBase64String(bytes);

2

Un linq à une ligne pour convertir un tableau d'octets byteArrFilenamelu à partir d'un fichier en une chaîne terminée par zéro de style C ascii pur serait le suivant: Pratique pour lire des choses comme les tables d'index de fichiers dans les anciens formats d'archive.

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

J'utilise '?'comme caractère par défaut pour tout ce qui n'est pas purement ascii ici, mais cela peut être changé, bien sûr. Si vous voulez être sûr de pouvoir le détecter, utilisez-le à la '\0'place, car TakeWhileau début, une chaîne construite de cette façon ne peut pas contenir de '\0'valeurs de la source d'entrée.


2

BitConverterpeut être utilisée pour convertir un fichier byte[]en string.

var convertedString = BitConverter.ToString(byteAttay);

La documentation de la BitConverterclasse peut être trouvée sur MSDN


1
Cela convertit le tableau d'octets en une chaîne hexadécimale représentant chaque octet, ce qui n'est généralement pas ce que vous souhaitez lors de la conversion d'octets en chaîne. Si c'est le cas, alors c'est une autre question, voir par exemple Comment convertir un tableau d'octets en chaîne hexadécimale, et vice versa? .
CodeCaster

Pas ce qu'OP a demandé
Winter

2

À ma connaissance, aucune des réponses fournies ne garantit un comportement correct avec une terminaison nulle. Jusqu'à ce que quelqu'un me montre différemment, j'ai écrit ma propre classe statique pour gérer cela avec les méthodes suivantes:

// 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);
}

La raison de cela startIndexétait dans l'exemple sur lequel je travaillais spécifiquement, j'avais besoin d'analyser un en byte[]tant que tableau de chaînes terminées par null. Il peut être ignoré en toute sécurité dans le cas simple


Le mien en fait. byteArr.TakeWhile(x => x != 0)est un moyen rapide et facile de résoudre le problème de terminaison nulle.
Nyerguds

1

hier est un résultat où vous n'avez pas eu à vous soucier de l'encodage. Je l'ai utilisé dans ma classe réseau et j'envoie des objets binaires sous forme de chaîne.

        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);
        }

n'en avait pas. Mais cette fonction est utilisée pour la transmission binaire dans notre réseau d'entreprise et jusqu'à présent, 20 To ont été ré-encodés correctement. Donc pour moi, cette fonction fonctionne :)
Marco Pardo

1

En plus de la réponse sélectionnée, si vous utilisez .NET35 ou .NET35 CE, vous devez spécifier l'index du premier octet à décoder et le nombre d'octets à décoder:

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

0

Essayez cette application 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

J'ai vu quelques réponses à ce poste et il est possible d'être considéré comme une connaissance de base complète, car plusieurs approches en programmation C # permettent de résoudre le même problème. Une seule chose qui doit être prise en compte concerne une différence entre Pure UTF-8 et UTF-8 avec BOM .

La semaine dernière, lors de mon travail, j'ai besoin de développer une fonctionnalité qui génère des fichiers CSV avec BOM et d'autres CSV avec UTF-8 pur (sans BOM), chaque type de codage de fichier CSV sera consommé par différentes API non standardisées, celle-là L'API a lu UTF-8 avec BOM et l'autre API a lu sans BOM. J'ai besoin de rechercher les références sur ce concept, en lisant " Quelle est la différence entre UTF-8 et UTF-8 sans nomenclature? " Discussion de débordement de pile et ce lien Wikipedia " Marque d'ordre d'octets " pour construire mon approche.

Enfin, ma programmation C # pour les deux types de codage UTF-8 (avec BOM et pure) devait être similaire à l'exemple ci-dessous:

//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);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.