Pertanyaan Bagaimana cara mendapatkan representasi byte string yang konsisten dalam C # tanpa menentukan enkoding secara manual?


Bagaimana cara mengonversi string ke a byte[] di .NET (C #) tanpa menentukan enkoding spesifik secara manual?

Saya akan mengenkripsi string. Saya dapat mengenkripsinya tanpa mengkonversi, tapi saya masih ingin tahu mengapa encoding datang untuk bermain di sini.

Juga, mengapa pengkodean harus dipertimbangkan? Tidak bisakah saya mendapatkan byte dari string yang telah disimpan? Mengapa ada ketergantungan pada pengkodean karakter?


1909
2018-01-23 13:39


asal


Jawaban:


Bertentangan dengan jawaban di sini, Anda TIDAK perlu khawatir tentang penyandian jika byte tidak perlu ditafsirkan!

Seperti yang Anda sebutkan, tujuan Anda adalah, hanya, untuk "dapatkan byte apa yang string telah disimpan di".
(Dan, tentu saja, untuk dapat membangun kembali string dari byte.)

Untuk tujuan itu, jujur ​​saya lakukan tidak pahamilah mengapa orang-orang terus memberi tahu Anda bahwa Anda memerlukan pengkodean. Anda tentu tidak perlu khawatir tentang pengkodean untuk ini.

Lakukan saja ini sebagai gantinya:

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

Selama program Anda (atau program lain) tidak mencoba menafsirkan byte entah bagaimana, yang Anda jelas tidak menyebutkan yang ingin Anda lakukan, maka ada tidak ada salah dengan pendekatan ini! Mengkhawatirkan pengkodean hanya membuat hidup Anda lebih rumit tanpa alasan nyata.

Manfaat tambahan untuk pendekatan ini:

Tidak masalah jika string berisi karakter yang tidak valid, karena Anda masih bisa mendapatkan data dan merekonstruksi string asli!

Ini akan dikodekan dan diterjemahkan persis sama, karena Anda hanya melihat byte.

Jika Anda menggunakan pengkodean tertentu, itu akan memberi Anda masalah dengan encoding / decoding karakter yang tidak valid.


1721
2018-04-30 07:44



Itu tergantung pada pengkodean string Anda (ASCII, UTF-8, ...).

Sebagai contoh:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

Contoh kecil mengapa enkode penting:

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII tidak dilengkapi dengan karakter khusus.

Secara internal, kerangka. NET menggunakan UTF-16 untuk merepresentasikan string, jadi jika Anda hanya ingin mendapatkan byte yang tepat yang digunakan .NET, gunakan System.Text.Encoding.Unicode.GetBytes (...).

Lihat Character Encoding dalam .NET Framework (MSDN) untuk informasi lebih lanjut.


1052
2018-01-23 13:43



Jawaban yang diterima sangat, sangat rumit. Gunakan kelas .NET yang disertakan untuk ini:

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

Jangan menemukan kembali roda jika Anda tidak perlu ...


245
2018-04-30 07:26



BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

105
2018-01-23 16:36



Anda perlu memasukkan pengkodean ke dalam akun, karena 1 karakter dapat diwakili oleh 1 atau lebih byte (hingga sekitar 6), dan pengkodean yang berbeda akan memperlakukan byte ini secara berbeda.

Joel memposting ini:

The Absolute Minimum Setiap Pengembang Perangkat Lunak Sepenuhnya, Positif Harus Tahu Tentang Unicode dan Set Karakter (Tidak Ada Alasan!)


79
2018-01-23 14:03



Ini pertanyaan yang populer. Penting untuk memahami apa yang ditanyakan oleh penulis pertanyaan, dan itu berbeda dari apa yang mungkin merupakan kebutuhan paling umum. Untuk mencegah penyalahgunaan kode yang tidak diperlukan, saya telah menjawabnya lebih dulu.

Kebutuhan umum

Setiap string memiliki set karakter dan encoding. Saat Anda mengonversi System.String keberatan dengan array System.Byte Anda masih memiliki set karakter dan encoding. Untuk sebagian besar penggunaan, Anda akan tahu set karakter dan encoding mana yang Anda perlukan dan .NET membuatnya mudah untuk "menyalin dengan konversi." Pilih saja yang tepat Encoding kelas.

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

Konversi mungkin perlu menangani kasus di mana kumpulan atau pengkodean karakter target tidak mendukung karakter yang ada di sumber. Anda memiliki beberapa pilihan: pengecualian, substitusi, atau skipping. Kebijakan default adalah mengganti '?'.

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

Jelas, konversi belum tentu lossless!

Catatan: Untuk System.String set karakter sumber adalah Unicode.

Satu-satunya hal yang membingungkan adalah bahwa. NET menggunakan nama set karakter untuk nama satu pengkodean tertentu dari set karakter tersebut. Encoding.Unicode harus dipanggil Encoding.UTF16.

Itu saja untuk sebagian besar penggunaan. Jika itu yang Anda butuhkan, berhenti membaca di sini. Lihat kesenangannya Artikel Joel Spolsky jika Anda tidak mengerti apa itu encoding.

Kebutuhan Spesifik

Sekarang, penulis pertanyaan bertanya, "Setiap string disimpan sebagai array byte, kan? Mengapa saya tidak bisa hanya memiliki byte itu?"

Dia tidak menginginkan konversi apa pun.

Dari C # spec:

Pengolahan karakter dan string dalam C # menggunakan pengkodean Unicode. Arang   type mewakili unit UTF-16 code, dan tipe string mewakili a   urutan unit kode UTF-16.

Jadi, kita tahu bahwa jika kita meminta konversi null (yaitu, dari UTF-16 ke UTF-16), kita akan mendapatkan hasil yang diinginkan:

Encoding.Unicode.GetBytes(".NET String to byte array")

Tetapi untuk menghindari penyebutan penyandian, kita harus melakukannya dengan cara lain. Jika suatu tipe data menengah dapat diterima, ada cara pintas konseptual untuk ini:

".NET String to byte array".ToCharArray()

Itu tidak membuat kita datatype yang diinginkan tetapi Jawaban Mehrdad menunjukkan bagaimana mengkonversi array Char ini ke array Byte menggunakan BlockCopy. Namun, ini menyalin string dua kali! Dan, itu juga secara eksplisit menggunakan kode khusus pengkodean: datatype System.Char.

Satu-satunya cara untuk mendapatkan byte aktual String disimpan di adalah dengan menggunakan pointer. Itu fixed pernyataan memungkinkan mengambil alamat nilai. Dari spesifikasi C #:

[Untuk] ekspresi jenis string, ... penginisialisasi menghitung   alamat karakter pertama dalam string.

Untuk melakukannya, kompilator menulis kode melompati bagian lain dari objek string dengan RuntimeHelpers.OffsetToStringData. Jadi, untuk mendapatkan byte mentah, cukup buat pointer ke string dan salin jumlah byte yang dibutuhkan.

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

Seperti yang ditunjukkan @CodesInChaos, hasilnya tergantung pada endianness mesin. Tetapi penulis pertanyaan tidak peduli dengan itu.


76
2017-12-02 04:43



Hanya untuk menunjukkan bahwa suara Mehrdrad menjawab bekerja, pendekatannya bahkan bisa bertahan karakter pengganti tidak berpasangan(di antaranya banyak yang menentang jawaban saya, tetapi semua orang sama-sama bersalah, misalnya System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytes; metode pengkodean tersebut tidak dapat mempertahankan karakter pengganti yang tinggi d800misalnya, dan itu hanya menggantikan karakter pengganti yang tinggi dengan nilai fffd ):

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }        
}

Keluaran:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

Cobalah dengan System.Text.Encoding.UTF8.GetBytes atau System.Text.Encoding.Unicode.GetBytes, mereka hanya akan mengganti karakter pengganti yang tinggi dengan nilai fffd

Setiap kali ada gerakan dalam pertanyaan ini, saya masih memikirkan seorang pembuat serial (entah itu dari Microsoft atau dari komponen pihak ketiga) yang dapat bertahan string bahkan berisi karakter pengganti yang tidak berpasangan; Saya google ini setiap sekarang dan kemudian: serialisasi karakter pengganti tidak berpasangan .NET. Ini tidak membuat saya kehilangan tidur, tetapi agak menjengkelkan ketika setiap sekarang dan kemudian ada seseorang yang mengomentari jawaban saya bahwa itu cacat, namun jawaban mereka sama-sama cacat ketika datang ke karakter pengganti yang tidak berpasangan.

Sial, Microsoft seharusnya baru saja digunakan System.Buffer.BlockCopy di dalamnya BinaryFormatter ツ

谢谢!


35
2017-07-25 22:52



Coba ini, kode jauh lebih sedikit:

System.Text.Encoding.UTF8.GetBytes("TEST String");

34
2018-01-23 15:54



Bagian pertama dari pertanyaan Anda (cara mendapatkan byte) sudah dijawab oleh orang lain: lihat di System.Text.Encoding ruang nama.

Saya akan menjawab pertanyaan lanjutan Anda: mengapa Anda harus memilih enkode? Kenapa kamu tidak bisa mendapatkannya dari kelas string itu sendiri?

Jawabannya ada dalam dua bagian.

Pertama-tama, byte yang digunakan secara internal oleh kelas string tidak masalah, dan kapan pun Anda berasumsi mereka mungkin akan memperkenalkan bug.

Jika program Anda sepenuhnya dalam dunia .Net maka Anda tidak perlu khawatir tentang mendapatkan array byte untuk string sama sekali, bahkan jika Anda mengirim data melalui jaringan. Sebaliknya, gunakan .Net Serialization untuk khawatir tentang transmisi data. Anda tidak perlu khawatir tentang byte aktual lagi: Pemformat serialisasi melakukannya untuk Anda.

Di sisi lain, bagaimana jika Anda mengirim byte ini di suatu tempat yang tidak dapat Anda jamin akan menarik data dari aliran serial .Net? Dalam hal ini Anda pasti perlu khawatir tentang encoding, karena jelas sistem eksternal ini peduli. Jadi sekali lagi, byte internal yang digunakan oleh string tidak masalah: Anda harus memilih pengkodean sehingga Anda dapat eksplisit tentang pengkodean ini pada penerima akhir, bahkan jika itu adalah pengkodean yang sama yang digunakan secara internal oleh .Net.

Saya mengerti bahwa dalam hal ini Anda mungkin lebih suka menggunakan byte aktual yang disimpan oleh variabel string dalam memori jika memungkinkan, dengan gagasan bahwa itu dapat menghemat pekerjaan membuat aliran byte Anda. Namun, saya taruh pada Anda itu tidak penting dibandingkan dengan memastikan bahwa output Anda dipahami di ujung yang lain, dan untuk menjamin bahwa Anda harus eksplisit dengan pengkodean Anda. Selain itu, jika Anda benar-benar ingin mencocokkan byte internal Anda, Anda sudah dapat memilih Unicode encoding, dan dapatkan penghematan kinerja itu.

Yang membawa saya ke bagian kedua ... memilih Unicode encoding aku s mengatakan. Net untuk menggunakan byte yang mendasari. Anda perlu memilih pengkodean ini, karena ketika beberapa Unicode-Plus yang baru muncul keluar. Runtime bersih harus bebas untuk menggunakan model pengkodean yang lebih baru dan lebih baik tanpa melanggar program Anda. Tapi, untuk saat ini (dan masa depan yang dapat dilihat), hanya memilih pengkodean Unicode memberi Anda apa yang Anda inginkan.

Penting juga untuk memahami string Anda harus ditulis ulang ke kawat, dan itu melibatkan setidaknya beberapa terjemahan dari pola bit bahkan ketika Anda menggunakan pengkodean yang cocok. Komputer perlu memperhitungkan hal-hal seperti Big vs Little Endian, urutan byte jaringan, packetisasi, informasi sesi, dll.


34
2018-03-10 08:57



Yah, saya sudah membaca semua jawaban dan mereka tentang menggunakan pengkodean atau satu tentang serialisasi yang menjatuhkan pengganti yang tidak berpasangan.

Ini buruk ketika string, misalnya, berasal SQL Server di mana ia dibangun dari susunan byte penyimpanan, misalnya, hash kata sandi. Jika kita menjatuhkan sesuatu dari itu, itu akan menyimpan hash yang tidak valid, dan jika kita ingin menyimpannya dalam XML, kita ingin membiarkannya tetap utuh (karena penulis XML menjatuhkan pengecualian pada pengganti yang tidak berpasangan yang ditemukannya).

Jadi saya gunakan Base64 pengkodean array byte dalam kasus-kasus seperti itu, tapi hei, di Internet hanya ada satu solusi untuk ini di C #, dan ada bug di dalamnya dan hanya ada satu cara, jadi saya memperbaiki bug dan prosedur tertulis kembali. Di sini Anda, calon karyawan Google di masa mendatang:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}

22
2017-07-16 11:45



Juga tolong jelaskan mengapa pengkodean harus dipertimbangkan.   Tidak bisakah saya mendapatkan byte dari string yang telah disimpan?   Mengapa ketergantungan ini pada encoding? !!!

Karena tidak ada yang namanya "byte string".

String (atau lebih umum, teks) terdiri dari karakter: huruf, angka, dan simbol lainnya. Itu saja. Komputer, bagaimanapun, tidak tahu apa-apa tentang karakter; mereka hanya bisa menangani byte. Oleh karena itu, jika Anda ingin menyimpan atau mengirim teks dengan menggunakan komputer, Anda perlu mengubah karakter menjadi byte. Bagaimana kamu melakukannya? Di sinilah pengkodean datang ke TKP.

Pengkodean hanyalah konvensi untuk menerjemahkan karakter logis ke byte fisik. Pengkodean yang paling sederhana dan paling dikenal adalah ASCII, dan itu semua yang Anda butuhkan jika Anda menulis dalam bahasa Inggris. Untuk bahasa lain, Anda memerlukan pengkodean yang lebih lengkap, karena salah satu pilihan Unicode adalah pilihan teraman saat ini.

Jadi, singkatnya, mencoba untuk "mendapatkan byte string tanpa menggunakan pengkodean" tidak mungkin sama seperti "menulis teks tanpa menggunakan bahasa apa pun".

By the way, saya sangat menyarankan Anda (dan siapa pun, dalam hal ini) untuk membaca ini sepotong kecil kebijaksanaan: The Absolute Minimum Setiap Pengembang Perangkat Lunak Sepenuhnya, Positif Harus Tahu Tentang Unicode dan Set Karakter (Tidak Ada Alasan!)


18
2018-06-05 10:52