วิธีการแปลง UTF-8 byte [] ถึง string?


932

ฉันมีbyte[]อาร์เรย์ที่ถูกโหลดจากแฟ้มที่เกิดขึ้นกับผมรู้จักกันมีUTF-8

ในรหัสการแก้จุดบกพร่องบางอย่างฉันต้องแปลงเป็นสตริง มีซับหนึ่งที่จะทำเช่นนี้?

ภายใต้ฝาครอบมันควรจะเป็นเพียงการจัดสรรและmemcopyดังนั้นแม้ว่ามันจะไม่ได้ถูกนำมาใช้ก็ควรจะเป็นไปได้


5
"ควรเป็นเพียงการจัดสรรและ memcopy": ไม่ถูกต้องเนื่องจากสตริง. NET เข้ารหัส UTF-16 อักขระ Unicode อาจเป็นหน่วยรหัส UTF-8 หนึ่งหน่วยหรือหน่วยรหัส UTF-16 หนึ่งหน่วย อื่นอาจเป็นสองหน่วยรหัส UTF-8 หรือหน่วยรหัส UTF-16 หนึ่งหน่วยอื่นอาจเป็นหน่วยรหัส UTF-8 สามหน่วยหรือหน่วยรหัส UTF-16 หนึ่งหน่วยอีกหน่วยหนึ่งอาจเป็นหน่วยรหัส UTF-8 สี่หน่วยหรือหน่วยรหัส UTF-16 สองหน่วย . memcopy อาจขยายได้ แต่จะไม่สามารถจัดการการแปลง UTF-8 เป็น UTF-16 ได้
Tom Blodget

คำตอบ:


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

13
มันจะจัดการกับสตริงสิ้นสุดเป็นโมฆะได้อย่างไร
maazza

14
@maazza ด้วยสาเหตุที่ไม่ทราบสาเหตุไม่ได้เลย System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');ฉันเรียกมันเหมือน
Hi-Angel

15
@ Hi-Angel เหตุผลที่ไม่รู้จัก? เหตุผลเดียวที่ทำให้สตริงที่สิ้นสุดด้วยค่า null เป็นที่นิยมคือภาษา C - และนั่นเป็นเพราะความผิดปกติในอดีต (คำสั่ง CPU ที่จัดการกับสตริงที่สิ้นสุดด้วยค่า null) .NET เพียงใช้สตริงโมฆะสิ้นสุดลงเมื่อ interopping ด้วยรหัสที่ใช้สตริงโมฆะสิ้นสุด (ซึ่งในที่สุดก็หายไป) มันใช้ได้อย่างสมบูรณ์แบบสำหรับสตริงที่มีอักขระ NUL และแน่นอนในขณะที่สตริงที่สิ้นสุดด้วยค่า null จะตายง่ายใน ASCII (เพียงสร้างจนกว่าคุณจะได้รับศูนย์ไบต์แรก) การเข้ารหัสอื่น ๆ รวมถึง UTF-8 นั้นไม่ง่ายเลย
Luaan

4
หนึ่งในคุณสมบัติที่สวยงามของ UTF-8 คือการเรียงลำดับที่สั้นกว่านั้นไม่ได้เป็นการเรียงลำดับของลำดับที่ยาวกว่า ดังนั้นสตริง UTF-8 ที่สิ้นสุดด้วย null จึงเป็นเรื่องง่าย
plugwash

10
ขอให้โชคดีในการเปิดกล่องถ้ามันไม่ใช่แบบ ascii เพียงใช้ Convert.ToBase64String
Erik Bergstedt

323

มีอย่างน้อยสี่วิธีในการทำ Conversion นี้

  1. GetString ของการเข้ารหัส
    แต่คุณจะไม่สามารถรับไบต์ต้นฉบับกลับมาได้หากไบต์เหล่านั้นมีอักขระที่ไม่ใช่ ASCII

  2. BitConverter.ToString
    ผลลัพธ์เป็นสตริง "-" ที่คั่นด้วย แต่ไม่มี. NET วิธีการในการแปลงสตริงกลับไปยังอาร์เรย์ไบต์

  3. Convert.ToBase64Stringคุณสามารถแปลงสตริงการส่งออกกลับไปยังอาร์เรย์ไบต์โดยใช้
    หมายเหตุ: สตริงผลลัพธ์อาจมี '+', '/' และ '=' หากคุณต้องการใช้สตริงใน URL คุณต้องเข้ารหัสอย่างชัดเจนConvert.FromBase64String

  4. HttpServerUtility.UrlTokenEncodeคุณสามารถแปลงสตริงการส่งออกกลับไปยังอาร์เรย์ไบต์โดยใช้
    HttpServerUtility.UrlTokenDecodeสตริงออกเป็นมิตรกับ URL แล้ว! ข้อเสียคือมันจำเป็นต้องมีการSystem.Webชุมนุมถ้าโครงการของคุณไม่ได้เป็นโครงการเว็บ

ตัวอย่างเต็มรูปแบบ:

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

โซลูชันทั่วไปสำหรับการแปลงจากอาร์เรย์ไบต์เป็นสตริงเมื่อคุณไม่ทราบว่ามีการเข้ารหัส:

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

3
แต่นี่ถือว่ามีการเข้ารหัส BOM ในไบต์สตรีมหรือว่าเป็น UTF-8 แต่คุณสามารถทำเช่นเดียวกันกับการเข้ารหัสต่อไป มันไม่ได้แก้ปัญหาได้อย่างน่าอัศจรรย์เมื่อคุณไม่รู้การเข้ารหัส
เซบาสเตียนแซนเดอร์

12

ความหมาย:

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

โดยใช้:

string result = input.ConvertByteToString();

9

การแปลง a byte[]ให้stringดูเหมือนง่าย แต่การเข้ารหัสชนิดใด ๆ มีแนวโน้มที่จะทำให้สายอักขระเอาต์พุตยุ่งเหยิง ฟังก์ชั่นเล็ก ๆ นี้ใช้งานได้โดยไม่มีผลลัพธ์ที่ไม่คาดคิด:

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

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

    return response;
}

ฉันได้รับ System.FormatException โดยใช้วิธีการของคุณเมื่อฉันคลายออกด้วย Convert.FromBase64String
Erik Bergstedt

@ AndrewJE สิ่งนี้จะใช้เวลาในการคำนวณแม้กระทั่งถ้าคุณมีอาร์เรย์ขนาดใหญ่เช่นที่ใช้จากรูปภาพ
user3841581

7

ใช้(byte)b.ToString("x2"), เอาท์พุทb4b5dfe475e58b67

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

นอกจากนี้ยังมีคลาส UnicodeEncoding การใช้งานค่อนข้างง่าย:

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

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

แต่ไม่ใช่ UTF-8 methinks?
david.pfx

1
UnicodeEncodingเป็นชื่อชั้นที่แย่ที่สุดที่เคยมีมา; unicode ไม่ใช่การเข้ารหัสเลย คลาสนั้นจริงๆแล้วเป็น UTF-16 ฉันคิดว่าเป็นเวอร์ชั่นเล็ก ๆ
Nyerguds


2

Linq one-liner สำหรับการแปลงอาร์เรย์ไบต์ที่byteArrFilenameอ่านจากไฟล์เป็นสตริงศูนย์สิ้นสุดแบบ Ascii C สไตล์บริสุทธิ์จะเป็นดังนี้: มีประโยชน์สำหรับการอ่านสิ่งต่าง ๆ เช่นตารางดัชนีไฟล์ในรูปแบบไฟล์เก็บถาวรเก่า

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

ฉันใช้'?'เป็น char เริ่มต้นสำหรับสิ่งที่ไม่ใช่ ascii บริสุทธิ์ที่นี่ แต่สามารถเปลี่ยนแปลงได้แน่นอน หากคุณต้องการให้แน่ใจว่าคุณสามารถตรวจจับได้เพียงใช้'\0'แทนเนื่องจากในTakeWhileตอนเริ่มต้นทำให้แน่ใจได้ว่าสตริงที่สร้างขึ้นด้วยวิธีนี้ไม่สามารถมี'\0'ค่าจากแหล่งอินพุตได้


2

BitConverterระดับสามารถใช้ในการแปลงไปbyte[]string

var convertedString = BitConverter.ToString(byteAttay);

เอกสารการBitConverterเรียนสามารถ fount บนMSDN


1
สิ่งนี้จะแปลงอาร์เรย์ไบต์เป็นสตริงเลขฐานสิบหกซึ่งแทนแต่ละไบต์ซึ่งโดยทั่วไปไม่ใช่สิ่งที่คุณต้องการเมื่อแปลงไบต์เป็นสตริง ถ้าคุณทำเช่นนั้นก็เป็นอีกคำถามหนึ่งดูตัวอย่างคุณแปลง Byte Array เป็น Hexadecimal String และในทางกลับกันได้อย่างไร .
CodeCaster

ไม่ใช่สิ่งที่ OP ถาม
ฤดูหนาว

2

เพื่อความรู้ของฉันไม่มีคำตอบที่กำหนดรับประกันพฤติกรรมที่ถูกต้องกับการยกเลิก null จนกว่าจะมีคนแสดงให้ฉันแตกต่างฉันเขียนคลาสคงที่ของฉันเองสำหรับการจัดการสิ่งนี้ด้วยวิธีการต่อไปนี้:

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

สาเหตุของการstartIndexเป็นในตัวอย่างที่ฉันกำลังทำงานโดยเฉพาะฉันต้องการที่จะแยกbyte[]เป็นอาร์เรย์ของสตริงที่สิ้นสุดโมฆะ สามารถละเว้นได้อย่างปลอดภัยในกรณีง่าย ๆ


ของฉันทำจริง byteArr.TakeWhile(x => x != 0)เป็นวิธีที่ง่ายและรวดเร็วในการแก้ปัญหาการยกเลิกค่า Null
Nyerguds

1

hier เป็นผลลัพธ์ที่คุณไม่ต้องกังวลกับการเข้ารหัส ฉันใช้มันในคลาสเครือข่ายของฉันและส่งวัตถุไบนารีเป็นสตริงด้วย

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

ไม่มีหนึ่ง แต่ฟังก์ชั่นนี้ใช้สำหรับการส่งสัญญาณแบบไบนารี่ในเครือข่าย บริษัท ของเราและอีก 20TB ได้ถูกเข้ารหัสใหม่อย่างถูกต้อง ดังนั้นสำหรับฉันฟังก์ชั่นนี้ทำงาน :)
มาร์โก Pardo

1

สำหรับคำตอบที่เลือกถ้าคุณใช้. NET35 หรือ. NET35 CE คุณจะต้องระบุดัชนีของไบต์แรกเพื่อถอดรหัสและจำนวนไบต์ที่จะถอดรหัส:

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

0

ลองแอปคอนโซลนี้:

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

ฉันเห็นคำตอบบางส่วนในโพสต์นี้และเป็นไปได้ที่จะพิจารณาความรู้พื้นฐานที่สมบูรณ์เนื่องจากมีหลายวิธีในการเขียนโปรแกรม C # เพื่อแก้ไขปัญหาเดียวกัน สิ่งเดียวที่จำเป็นต้องพิจารณาคือความแตกต่างระหว่างPure UTF-8และUTF-8 กับ BOMBOM

ในสัปดาห์ที่แล้วที่งานของฉันฉันต้องพัฒนาฟังก์ชั่นหนึ่งที่ส่งออกไฟล์ CSV พร้อม BOM และ CSV อื่น ๆ ที่มี UTF-8 แท้ (ไม่มี BOM) ไฟล์ CSV แต่ละประเภทจะใช้การเข้ารหัสโดย API ที่ไม่ได้มาตรฐานที่แตกต่างกัน API อ่าน UTF-8 พร้อม BOM และ API อื่น ๆ อ่านโดยไม่มี BOM ฉันต้องการค้นคว้าข้อมูลอ้างอิงเกี่ยวกับแนวคิดนี้การอ่าน " ความแตกต่างระหว่าง UTF-8 และ UTF-8 โดยไม่ใช้ BOM คืออะไร " การอภิปรายสแต็คโอเวอร์โฟลว์และลิงค์วิกิพีเดีย " เครื่องหมายลำดับไบต์ " เพื่อสร้างแนวทางของฉัน

สุดท้ายการเขียนโปรแกรม C # ของฉันสำหรับประเภทการเข้ารหัส UTF-8 (ที่มี BOM และบริสุทธิ์) จำเป็นต้องคล้ายกันดังตัวอย่างนี้:

//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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.