Wie konvertiere ich UTF-8 Byte [] in String?

932

Ich habe ein byte[]Array, das aus einer mir bekannten Datei geladen wird und UTF-8 enthält .

In einigen Debugging-Codes muss ich es in eine Zeichenfolge konvertieren. Gibt es einen Einzeiler, der dies erledigt?

Unter dem Deckmantel sollte es nur eine Zuordnung und eine Memkopie sein , also sollte es möglich sein , auch wenn es nicht implementiert ist.

BCS
quelle
5
"sollte nur eine Zuordnung und eine Kopie sein": ist nicht korrekt, da eine .NET-Zeichenfolge UTF-16-codiert ist. Ein Unicode-Zeichen kann eine UTF-8-Codeeinheit oder eine UTF-16-Codeeinheit sein. Eine andere kann aus zwei UTF-8-Codeeinheiten oder einer UTF-16-Codeeinheit bestehen, eine andere aus drei UTF-8-Codeeinheiten oder einer UTF-16-Codeeinheit, eine andere aus vier UTF-8-Codeeinheiten oder zwei UTF-16-Codeeinheiten . Eine Memcopy kann möglicherweise erweitert werden, kann jedoch die Konvertierung von UTF-8 in UTF-16 nicht verarbeiten.
Tom Blodget

Antworten:

1470
string result = System.Text.Encoding.UTF8.GetString(byteArray);
Zanoni
quelle
13
Wie geht es mit nullenden Zeichenfolgen um?
Maazza
14
@maazza aus unbekannten Gründen überhaupt nicht. Ich nenne es so System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
Hi-Angel
15
@ Hi-Angel Unbekannter Grund? Der einzige Grund, warum nullterminierte Zeichenfolgen jemals populär wurden, war die C-Sprache - und selbst das war nur auf eine historische Kuriosität zurückzuführen (CPU-Anweisungen, die sich mit nullterminierten Zeichenfolgen befassten). .NET verwendet nur nullterminierte Zeichenfolgen, wenn es mit Code zusammenarbeitet, der nullterminierte Zeichenfolgen verwendet (die schließlich verschwinden). Es ist vollkommen gültig, wenn eine Zeichenfolge NUL-Zeichen enthält. Und während nullterminierte Zeichenfolgen in ASCII kinderleicht sind (nur erstellen, bis Sie das erste Null-Byte erhalten), sind andere Codierungen, einschließlich UTF-8, natürlich nicht so einfach.
Luaan
4
Eines der schönen Merkmale von UTF-8 ist, dass eine kürzere Sequenz niemals eine Teilsequenz einer längeren Sequenz ist. Eine nullterminierte UTF-8-Zeichenfolge ist also einfach.
Plugwash
10
Nun, viel Glück beim Auspacken, wenn es nicht-ASCII hat. Verwenden Sie einfach Convert.ToBase64String.
Erik Bergstedt
323

Es gibt mindestens vier verschiedene Möglichkeiten, diese Konvertierung durchzuführen.

  1. GetString von Encoding
    , aber Sie können die ursprünglichen Bytes nicht zurückerhalten, wenn diese Bytes Nicht-ASCII-Zeichen enthalten.

  2. BitConverter.ToString
    Die Ausgabe ist eine durch "-" getrennte Zeichenfolge, es gibt jedoch keine in .NET integrierte Methode, um die Zeichenfolge zurück in ein Byte-Array zu konvertieren.

  3. Convert.ToBase64String Mit können
    Sie die Ausgabezeichenfolge einfach wieder in ein Byte-Array konvertieren Convert.FromBase64String.
    Hinweis: Die Ausgabezeichenfolge kann '+', '/' und '=' enthalten. Wenn Sie die Zeichenfolge in einer URL verwenden möchten, müssen Sie sie explizit codieren.

  4. HttpServerUtility.UrlTokenEncode Mit können
    Sie die Ausgabezeichenfolge einfach wieder in ein Byte-Array konvertieren HttpServerUtility.UrlTokenDecode. Die Ausgabezeichenfolge ist bereits URL-freundlich! Der Nachteil ist, dass eine System.WebMontage erforderlich ist, wenn Ihr Projekt kein Webprojekt ist.

Ein vollständiges Beispiel:

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

Eine allgemeine Lösung zum Konvertieren von Bytearray in Zeichenfolge, wenn Sie die Codierung nicht kennen:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}
Nir
quelle
3
Dies setzt jedoch voraus, dass sich entweder eine Codierungsstückliste im Bytestream befindet oder dass sie sich in UTF-8 befindet. Aber Sie können das gleiche mit Encoding tun. Es löst das Problem nicht auf magische Weise, wenn Sie die Codierung nicht kennen.
Sebastian Zander
12

Definition:

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

Verwenden von:

string result = input.ConvertByteToString();
Erçin Dedeoğlu
quelle
9

Das Konvertieren von a byte[]in a stringscheint einfach zu sein, aber jede Art von Codierung kann die Ausgabezeichenfolge durcheinander bringen. Diese kleine Funktion funktioniert nur ohne unerwartete Ergebnisse:

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

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

    return response;
}
AndrewJE
quelle
Ich habe System.FormatException mit Ihrer Methode erhalten, als ich sie mit Convert.FromBase64String entpackt habe.
Erik Bergstedt
@ AndrewJE Dies dauert sogar für die Berechnung, wenn Sie ein großes Byte-Array haben, wie es auf den Bildern verwendet wird.
user3841581
7

Verwenden von (byte)b.ToString("x2")Ausgängenb4b5dfe475e58b67

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

}
Metadings
quelle
4

Es gibt auch die Klasse UnicodeEncoding, die recht einfach zu verwenden ist:

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

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));
PK
quelle
Aber nicht UTF-8-Methoden?
david.pfx
1
UnicodeEncodingist der schlechteste Klassenname aller Zeiten; Unicode ist überhaupt keine Codierung. Diese Klasse ist eigentlich UTF-16. Die Little-Endian-Version, denke ich.
Nyerguds
3

Alternative:

 var byteStr = Convert.ToBase64String(bytes);
Fehr
quelle
2

Ein Linq-Einzeiler zum Konvertieren eines byteArrFilenameaus einer Datei gelesenen Byte-Arrays in eine reine ASCII-Zeichenfolge mit nullter Endung wäre: Praktisch zum Lesen von Dingen wie Dateiindex-Tabellen in alten Archivformaten.

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

Ich verwende hier '?'als Standardzeichen alles, was nicht rein ASCII ist, aber das kann natürlich geändert werden. Wenn Sie sicher sein möchten, dass Sie es erkennen können, verwenden Sie '\0'stattdessen einfach , da das TakeWhileam Anfang sicherstellt, dass eine auf diese Weise erstellte Zeichenfolge möglicherweise keine '\0'Werte aus der Eingabequelle enthalten kann .

Nyerguds
quelle
2

BitConverterKlasse kann verwendet werden, um ein byte[]in zu konvertieren string.

var convertedString = BitConverter.ToString(byteAttay);

Die Dokumentation der BitConverterKlasse kann auf MSDN erfolgen

Sagar
quelle
1
Dadurch wird das Byte-Array in eine hexadezimale Zeichenfolge konvertiert, die jedes Byte darstellt. Dies ist im Allgemeinen nicht das, was Sie beim Konvertieren von Bytes in eine Zeichenfolge wünschen. Wenn Sie dies tun, ist dies eine andere Frage. Siehe beispielsweise Wie konvertieren Sie das Byte-Array in eine hexadezimale Zeichenfolge und umgekehrt? .
CodeCaster
Nicht was OP gefragt hat
Winter
2

Meines Wissens garantiert keine der angegebenen Antworten ein korrektes Verhalten bei Nullbeendigung. Bis mich jemand anders zeigt, habe ich meine eigene statische Klasse geschrieben, um dies mit den folgenden Methoden zu behandeln:

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

Der Grund für das startIndexwar in dem Beispiel, an dem ich speziell arbeitete, dass ich a byte[]als Array von nullterminierten Zeichenfolgen analysieren musste . Es kann im einfachen Fall sicher ignoriert werden

Assimilater
quelle
Meins tatsächlich. byteArr.TakeWhile(x => x != 0)ist eine schnelle und einfache Möglichkeit, das Problem der Nullterminierung zu lösen.
Nyerguds
1

Hier ist ein Ergebnis, bei dem Sie sich nicht um die Codierung kümmern mussten. Ich habe es in meiner Netzwerkklasse verwendet und binäre Objekte als String damit gesendet.

        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);
        }
Marco Pardo
quelle
hatte keinen. Diese Funktion wird jedoch für die binäre Übertragung in unserem Unternehmensnetzwerk verwendet. Bisher wurden 20 TB neu codiert. Also für mich funktioniert diese Funktion :)
Marco Pardo
1

Wenn Sie .NET35 oder .NET35 CE verwenden, müssen Sie zusätzlich zur ausgewählten Antwort den Index des ersten zu decodierenden Bytes und die Anzahl der zu decodierenden Bytes angeben:

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

Probieren Sie diese Konsolen-App aus:

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);
}
RM Shahidul Islam Shahed
quelle
0

Ich habe in diesem Beitrag einige Antworten gesehen und es ist möglich, als abgeschlossenes Basiswissen zu gelten, da es in der C # -Programmierung verschiedene Ansätze gibt, um dasselbe Problem zu lösen. Es muss nur ein Unterschied zwischen Pure UTF-8 und UTF-8 mit Stückliste berücksichtigt werden .

In der letzten Woche muss ich bei meiner Arbeit eine Funktionalität entwickeln, die CSV-Dateien mit Stückliste und andere CSVs mit reinem UTF-8 (ohne Stückliste) ausgibt. Jeder CSV-Dateikodierungstyp wird von verschiedenen nicht standardisierten APIs verwendet, nämlich dieser API liest UTF-8 mit Stückliste und die andere API liest ohne Stückliste. Ich muss die Referenzen zu diesem Konzept recherchieren und lesen " Was ist der Unterschied zwischen UTF-8 und UTF-8 ohne Stückliste? ". Diskussion über Stapelüberlauf und diesen Wikipedia-Link " Byte Order Mark ", um meinen Ansatz zu erstellen.

Schließlich musste meine C # -Programmierung für die beiden UTF-8-Codierungstypen (mit Stückliste und rein) ähnlich sein wie in diesem Beispiel unten:

//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);
Antonio Leonardo
quelle