Nasıl UTF-8 byte [] dönüştürmek için dize?


932

UTF-8byte[] içeren bilinen bir dosyadan yüklenen bir dizi var .

Bazı hata ayıklama kodunda, bir dizeye dönüştürmek gerekiyor. Bunu yapacak bir astar var mı?

Kapakların altında sadece bir tahsis ve bir not olması gerekir , bu yüzden uygulanmasa bile mümkün olmalıdır.


5
"bir ayırma ve bir memcopy olmalıdır": bir .NET dizesi UTF-16 kodlu olduğundan doğru değil. Unicode karakter bir UTF-8 kod birimi veya bir UTF-16 kod birimi olabilir. diğeri iki UTF-8 kod birimi veya bir UTF-16 kod birimi olabilir, diğeri üç UTF-8 kod birimi veya bir UTF-16 kod birimi olabilir, diğeri dört UTF-8 kod birimi veya iki UTF-16 kod birimi olabilir . Bir memcopy genişleyebilir ancak UTF-8'den UTF-16'ya dönüştürme işlemi yapamaz.
Tom Blodget

Yanıtlar:


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

13
boş uçlu dizeleri nasıl işler?
maazza

14
@maazza bilinmeyen bir nedenden dolayı hiç değil. Ben öyle diyorum System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
Hi-Angel

15
@ Hi-Angel Bilinmeyen neden? Boş sonlandırılmış dizelerin popüler olmasının tek nedeni C diliydi - ve bu bile yalnızca tarihsel tuhaflıktan kaynaklanıyordu (boş değerli sonlandırılmış dizelerle ilgilenen CPU talimatları). .NET, null sonlu dizeleri ( son olarak kaybolan) kullanan kodla birlikte çalışırken yalnızca null sonlu dizeleri kullanır . Bir dizenin NUL karakterlerini içermesi mükemmel bir şekilde geçerlidir. Ve elbette, boş sonlandırılmış dizeler ASCII'de basitken (sadece ilk sıfır baytı alana kadar inşa et), UTF-8 dahil diğer kodlamalar o kadar basit değildir.
Luaan

4
UTF-8'in güzel özelliklerinden biri, daha kısa bir dizinin asla daha uzun bir dizinin bir dizisi olmamasıdır. Bu nedenle, boş bir sonlandırılmış UTF-8 dizesi basittir.
plugwash

10
Ascii olmayan varsa açmak iyi şanslar. Convert.ToBase64String öğesini kullanmanız yeterlidir.
Erik Bergstedt

323

Bu dönüşümü yapmanın en az dört farklı yolu vardır.

  1. Kodlama GetString
    , ancak bu baytların ASCII olmayan karakterleri varsa orijinal baytları geri alamazsınız.

  2. BitConverter.ToString
    Çıktı "-" ile ayrılmış bir dizedir, ancak dizeyi bayt dizisine dönüştürmek için .NET yerleşik bir yöntemi yoktur.

  3. Convert.ToBase64String
    Çıktı dizesini kullanarak bayt dizisine kolayca dönüştürebilirsiniz Convert.FromBase64String.
    Not: Çıktı dizesi '+', '/' ve '=' içerebilir. Dizeyi bir URL'de kullanmak istiyorsanız, dizeyi açıkça kodlamanız gerekir.

  4. HttpServerUtility.UrlTokenEncode
    Çıktı dizesini kullanarak bayt dizisine kolayca dönüştürebilirsiniz HttpServerUtility.UrlTokenDecode. Çıkış dizesi zaten URL dostu! Dezavantajı, System.Webprojeniz bir web projesi değilse, montaj gerektirmesidir .

Tam bir örnek:

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

Kodlamayı bilmediğinizde bayt dizisinden dizeye dönüştürmek için genel bir çözüm:

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

3
Ancak bu, bayt akışında bir kodlama BOM'si olduğunu veya UTF-8'de olduğunu varsayar. Ama yine de aynısını Kodlama ile yapabilirsiniz. Kodlamayı bilmediğinizde sorunu sihirli bir şekilde çözmez.
Sebastian Zander

12

Tanım:

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

Kullanımı:

string result = input.ConvertByteToString();

9

Bir dönüştürme byte[]a stringbasit görünüyor ama kodlama her türlü çıkış dize kadar karışıklık muhtemeldir. Bu küçük işlev beklenmedik sonuçlar olmadan çalışır:

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

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

    return response;
}

Convert.FromBase64String ile paketini açtığımda System.FormatException yönteminizi kullanarak aldım.
Erik Bergstedt

@ AndrewJE Bu resimlerden kullanılan gibi büyük bir bayt diziniz varsa bile hesaplamak için alacaktır.
user3841581

7

Kullanma (byte)b.ToString("x2"), Çıktılarb4b5dfe475e58b67

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

Ayrıca, kullanımı oldukça basit olan UnicodeEncoding sınıfı da vardır:

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

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

Ama UTF-8 methinks değil mi?
david.pfx

1
UnicodeEncodingşimdiye kadarki en kötü sınıf adı; unicode hiç bir kodlama değildir. Bu sınıf aslında UTF-16. Küçük endian versiyonu, sanırım.
Nyerguds

3

Alternatif:

 var byteStr = Convert.ToBase64String(bytes);

2

Bir byteArrFilenamedosyadan okunan bir bayt dizisini saf bir ascii C stili sıfır sonlu dizeye dönüştürmek için Linq bir astar şu olurdu: Eski arşiv formatlarında dosya dizin tabloları gibi şeyleri okumak için kullanışlı.

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

'?'Burada saf ascii olmayan bir şey için varsayılan karakter olarak kullanıyorum , ama elbette değiştirilebilir. Tespit edebileceğinizden emin olmak istiyorsanız, '\0'bunun yerine kullanın, çünkü TakeWhilebaşlangıçta bu şekilde oluşturulmuş bir dizenin '\0'giriş kaynağından değerler içeremeyeceğini garanti eder .


2

BitConvertersınıf dönüştürmek için kullanılabilir byte[]için string.

var convertedString = BitConverter.ToString(byteAttay);

BitConverterSınıf belgeleri MSDN'de yayınlanabilir


1
Bu, bayt dizisini, her baytı temsil eden onaltılık bir dizeye dönüştürür; bu, baytları bir dizeye dönüştürürken genellikle istediğiniz gibi değildir. Bunu yaparsanız, bu başka bir soru, bkz. Örneğin Bayt Dizisini Onaltılı Dizeye nasıl dönüştürürsünüz? .
CodeCaster

OP'nin
Kış

2

Bildiğim kadarıyla verilen cevapların hiçbiri null sonlandırmayla doğru davranışı garanti etmez. Birisi bana farklı gösterene kadar, aşağıdaki yöntemlerle bunu yapmak için kendi statik sınıfımı yazdım:

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

Bunun nedeni startIndexözellikle üzerinde çalışıyordu örnek oldu byte[]bir boş sonlandırılmış dizeler dizisi olarak ayrıştırmak gerekiyordu . Basit durumda güvenle göz ardı edilebilir


Benimki aslında. byteArr.TakeWhile(x => x != 0)sıfır sonlandırma sorununu çözmenin hızlı ve kolay bir yoludur.
Nyerguds

1

hier, kodlama ile uğraşmak zorunda olmadığınız bir sonuçtur. Ağ sınıfımda kullandım ve ikili nesneleri onunla dize olarak gönderdim.

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

bir tane yoktu. Ancak bu işlev şirket ağımızdaki ikili iletim için kullanılmaktadır ve şu ana kadar 20 TB yeniden doğru şekilde kodlanmıştır. Yani benim için bu fonksiyon işe yarıyor :)
Marco Pardo

1

Seçilen cevaba ek olarak, .NET35 veya .NET35 CE kullanıyorsanız, kodu çözülecek ilk bayt dizini ve kodunu çözecek bayt sayısını belirtmeniz gerekir:

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

0

Bu konsol uygulamasını deneyin:

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

Bu yazıda bazı cevaplar gördüm ve tamamlanmış temel bilgi olarak kabul edilebilir, çünkü aynı sorunu çözmek için C # Programlama'da birkaç yaklaşım var. Dikkate alınması gereken tek şey, Saf UTF-8 ve BOM ile UTF-8 arasındaki fark hakkında .

Geçen hafta, işimde, BOM ile CSV dosyalarını ve saf UTF-8 (BOM olmadan) diğer CSV'leri çıkaran bir işlevsellik geliştirmem gerekiyor, her CSV dosyası Kodlama türü farklı standart olmayan API'ler tarafından kullanılacak API, BOM ile UTF-8 ve BOM olmadan okunan diğer API'yı okur. Okumayı, bu kavram hakkında referanslar konusunda araştırma yapmak isteyen " BOM olmadan UTF-8 ve UTF-8 arasındaki fark nedir? " Yığın taşması tartışma ve bu Wikipedia linki " Bayt sırası işareti " yaklaşımım inşa etmek.

Son olarak, her iki UTF-8 kodlama türü (BOM ve saf) için C # Programlama aşağıdaki örnek gibi benzer olması gerekiyordu:

//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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.