Câu hỏi Làm thế nào để có được một biểu diễn byte nhất quán của các chuỗi trong C # mà không cần chỉ định một cách mã hóa bằng tay?


Làm cách nào để chuyển đổi một string đến một byte[] trong .NET (C #) mà không cần chỉ định bằng tay một mã hóa cụ thể?

Tôi sẽ mã hóa chuỗi. Tôi có thể mã hóa nó mà không cần chuyển đổi, nhưng tôi vẫn muốn biết lý do mã hóa xuất hiện ở đây.

Ngoài ra, tại sao nên mã hóa được xem xét? Tôi không thể đơn giản nhận được những gì byte chuỗi đã được lưu trữ trong? Tại sao lại có sự phụ thuộc vào mã hóa ký tự?


1912
2018-01-23 13:39


gốc


Mỗi chuỗi được lưu trữ dưới dạng một mảng byte phải không? Tại sao tôi không thể đơn giản có những byte đó? - Agnel Kurian
Mã hóa Là những gì ánh xạ các ký tự cho các byte. Ví dụ, trong ASCII, chữ 'A' ánh xạ tới số 65. Trong một bảng mã khác, nó có thể không giống nhau. Cách tiếp cận cấp cao đối với các chuỗi được thực hiện trong khung công tác .NET làm cho điều này phần lớn không liên quan, mặc dù (ngoại trừ trong trường hợp này). - Lucas Jones
Để chơi chủ trương của ma quỷ: Nếu bạn muốn nhận các byte của một chuỗi trong bộ nhớ (như .NET sử dụng chúng) và thao tác chúng bằng cách nào đó (ví dụ CRC32), và KHÔNG BAO GIỜ EVER muốn giải mã nó trở lại chuỗi ban đầu ... không thẳng về phía trước tại sao bạn quan tâm đến mã hóa hoặc cách bạn chọn loại mã hóa nào. - Greg
Ngạc nhiên không ai đã cung cấp liên kết này: joelonsoftware.com/articles/Unicode.html - Bevan
Một char không phải là một byte và byte không phải là một char. Một char là cả một chìa khóa vào một bảng font chữ và một truyền thống từ vựng. Chuỗi là chuỗi ký tự. (Một từ, đoạn văn, câu, và tiêu đề cũng có truyền thống từ vựng riêng của họ mà biện minh cho định nghĩa kiểu riêng của họ - nhưng tôi digress). Giống như số nguyên, số dấu chấm động và mọi thứ khác, ký tự được mã hóa thành byte. Đã có một thời gian khi mã hóa đơn giản là một: ASCII. Tuy nhiên, để chứa tất cả các mã vạch của con người, 256 hoán vị của một byte là không đủ và mã hóa được đưa ra để chọn lọc sử dụng nhiều byte hơn. - George


Các câu trả lời:


Trái ngược với câu trả lời ở đây, bạn KHÔNG cần phải lo lắng về việc mã hóa nếu các byte không cần phải được giải thích!

Như bạn đã đề cập, mục tiêu của bạn là, đơn giản, "lấy chuỗi byte đã được lưu trữ trong".
(Và, tất nhiên, để có thể xây dựng lại chuỗi từ các byte.)

Đối với những mục tiêu đó, tôi thành thật làm không phải hiểu tại sao mọi người cứ nói với bạn rằng bạn cần mã hóa. Bạn chắc chắn KHÔNG cần phải lo lắng về việc mã hóa cho việc này.

Chỉ cần làm điều này thay vào đó:

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

Miễn là chương trình của bạn (hoặc các chương trình khác) không cố gắng thông dịch các byte bằng cách nào đó, mà bạn rõ ràng đã không đề cập đến bạn có ý định làm, sau đó có không có gì sai với cách tiếp cận này! Lo lắng về việc mã hóa chỉ khiến cuộc sống của bạn trở nên phức tạp hơn mà không có lý do thực sự nào.

Lợi ích bổ sung cho phương pháp này:

Nó không quan trọng nếu chuỗi chứa các ký tự không hợp lệ, bởi vì bạn vẫn có thể lấy dữ liệu và tái tạo lại chuỗi gốc!

Nó sẽ được mã hóa và giải mã chỉ giống nhau, bởi vì bạn chỉ nhìn vào các byte.

Tuy nhiên, nếu bạn đã sử dụng một mã hóa cụ thể, nó sẽ cho bạn sự cố khi mã hóa / giải mã các ký tự không hợp lệ.


1719
2018-04-30 07:44



Điều xấu xí về cái này là, GetString và GetBytes cần thực hiện trên một hệ thống có cùng độ bền để hoạt động. Vì vậy, bạn không thể sử dụng để có được byte bạn muốn biến thành một chuỗi ở nơi khác. Vì vậy, tôi có một thời gian khó khăn để đưa ra một tình huống mà tôi muốn sử dụng điều này. - CodesInChaos
@CodeInChaos: Giống như tôi đã nói, toàn bộ vấn đề này là nếu bạn muốn sử dụng nó trên cùng một loại hệ thống, với cùng một tập hợp các chức năng. Nếu không, thì bạn không nên sử dụng nó. - Mehrdad
-1 Tôi đảm bảo rằng ai đó (những người không hiểu byte vs ký tự) sẽ muốn chuyển đổi chuỗi của họ thành một mảng byte, họ sẽ google nó và đọc câu trả lời này, và họ sẽ làm điều sai, bởi vì trong hầu như tất cả trường hợp, mã hóa LÀ liên quan, thích hợp. - artbristol
@artbristol: Nếu họ không thể bị làm phiền để đọc câu trả lời (hoặc các câu trả lời khác ...), thì tôi xin lỗi, vậy thì không có cách nào tốt hơn để tôi giao tiếp với họ. Tôi thường chọn trả lời OP thay vì cố gắng đoán xem người khác có thể làm gì với câu trả lời của tôi - OP có quyền được biết và chỉ vì ai đó có thể lạm dụng con dao không có nghĩa là chúng ta cần giấu tất cả các con dao trên thế giới cho chính chúng ta. Mặc dù nếu bạn không đồng ý đó là tốt quá. - Mehrdad
Câu trả lời này là sai trên rất nhiều cấp độ nhưng quan trọng nhất vì nó decleration "bạn KHÔNG cần phải lo lắng về mã hóa!". Hai phương thức, GetBytes và GetString là thừa trong nhiều như chúng chỉ đơn thuần là tái triển khai những gì Encoding.Unicode.GetBytes () và Encoding.Unicode.GetString () đã làm. Câu lệnh "Miễn là chương trình của bạn (hoặc các chương trình khác) không cố gắng diễn dịch các byte" cũng về cơ bản là thiếu sót như chúng ngụ ý các byte nên được hiểu là Unicode. - David


Nó phụ thuộc vào việc mã hóa chuỗi của bạn (ASCII, UTF-8, ...).

Ví dụ:

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

Một mẫu nhỏ tại sao mã hóa lại quan trọng:

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 chỉ đơn giản là không được trang bị để đối phó với các ký tự đặc biệt.

Bên trong, khuôn khổ .NET sử dụng UTF-16 để biểu diễn các chuỗi, vì vậy nếu bạn chỉ muốn nhận các byte chính xác mà .NET sử dụng, hãy sử dụng System.Text.Encoding.Unicode.GetBytes (...).

Xem Mã hóa ký tự trong Khuôn khổ .NET (MSDN) để biết thêm thông tin.


1052
2018-01-23 13:43



Nhưng, tại sao nên mã hóa được xem xét? Tại sao tôi không thể đơn giản nhận được các byte mà không cần phải xem mã hóa nào đang được sử dụng? Ngay cả khi nó được yêu cầu, không phải là đối tượng String chính nó biết những gì đang được sử dụng mã hóa và chỉ cần đổ những gì có trong bộ nhớ? - Agnel Kurian
Một chuỗi .NET luôn được mã hóa dưới dạng Unicode. Vì vậy, hãy sử dụng System.Text.Encoding.Unicode.GetBytes (); để có được tập hợp các byte mà .NET sẽ sử dụng để biểu diễn các ký tự. Tuy nhiên tại sao bạn muốn điều đó? Tôi khuyên bạn nên sử dụng UTF-8 đặc biệt là khi hầu hết các nhân vật trong bộ Latin phía tây. - AnthonyWJones
Ngoài ra: các byte chính xác được sử dụng nội bộ trong chuỗi không quan trọng nếu hệ thống truy xuất chúng không xử lý mã hóa đó hoặc xử lý nó dưới dạng mã hóa sai. Nếu tất cả nằm trong .Net, tại sao lại chuyển đổi thành một mảng byte. Nếu không, tốt hơn là phải rõ ràng bằng mã hóa của bạn - Joel Coehoorn
@ Jelel, Hãy cẩn thận với System.Text.Encoding.Default vì nó có thể khác nhau trên mỗi máy được chạy. Đó là lý do tại sao chúng tôi khuyên bạn nên luôn chỉ định mã hóa, chẳng hạn như UTF-8. - Ash
Bạn không cần mã hóa trừ khi bạn (hoặc người khác) thực sự dự định (s) để thông dịch dữ liệu, thay vì coi nó là "khối byte" chung chung. Đối với những thứ như nén, mã hóa, vv, lo lắng về việc mã hóa là vô nghĩa. Xem câu trả lời của tôi cho một cách để làm điều này mà không cần lo lắng về việc mã hóa. (Tôi có thể đã đưa ra một -1 cho rằng bạn cần phải lo lắng về mã hóa khi bạn không, nhưng tôi không cảm thấy đặc biệt có ý nghĩa ngày hôm nay.: P) - Mehrdad


Câu trả lời được chấp nhận là rất, rất phức tạp. Sử dụng các lớp .NET bao gồm cho điều này:

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

Đừng sáng tạo lại bánh xe nếu bạn không phải ...


245
2018-04-30 07:26



Câu trả lời được chấp nhận không chỉ rất phức tạp mà còn là một công thức cho thảm họa. - Konamiman
Trong trường hợp câu trả lời được chấp nhận bị thay đổi, vì mục đích ghi lại, đó là câu trả lời của Mehrdad tại thời điểm hiện tại và ngày tháng. Hy vọng rằng OP sẽ xem xét lại điều này và chấp nhận một giải pháp tốt hơn. - Thomas Eding
tốt về nguyên tắc nhưng, mã hóa phải là System.Text.Encoding.Unicode tương đương với câu trả lời của Mehrdad. - Jodrell
Câu hỏi đã được chỉnh sửa một triệu lần kể từ khi câu trả lời ban đầu, vì vậy, có lẽ câu trả lời của tôi là một chút lỗi thời. Tôi không bao giờ có ý định cung cấp cho một exace tương đương với câu trả lời của Mehrdad, nhưng đưa ra một cách hợp lý để làm điều đó. Nhưng, bạn có thể đúng. Tuy nhiên, cụm từ "nhận được những gì byte chuỗi đã được lưu trữ trong" trong câu hỏi ban đầu là rất không chắc chắn. Được lưu trữ, ở đâu? Trong trí nhớ? Trên đĩa? Nếu trong bộ nhớ, System.Text.Encoding.Unicode.GetBytes có lẽ sẽ chính xác hơn. - Erik A. Brandstadmoen
@AMissico, đề xuất của bạn là lỗi, trừ khi bạn chắc chắn chuỗi của mình tương thích với mã hóa mặc định của hệ thống (chuỗi chỉ chứa ký tự ASCII trong bộ ký tự cũ mặc định của hệ thống). Nhưng không nơi nào OP nói. - Frédéric


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



Bạn có thể sử dụng cùng một cá thể BinaryFormatter cho tất cả các hoạt động đó - Joel Coehoorn
Rất thú vị. Rõ ràng nó sẽ thả bất kỳ ký tự Unicode thay thế cao nào. Xem tài liệu trên [BinaryFormatter] - John Robertson
@ ErikA.Brandstadmoen Xem các bài kiểm tra của tôi ở đây: stackoverflow.com/a/10384024 - Michael Buen


Bạn cần phải đưa mã hóa vào tài khoản, bởi vì 1 ký tự có thể được biểu diễn bằng 1 Hoặc nhiều hơn byte (tối đa khoảng 6) và các mã hóa khác nhau sẽ xử lý các byte khác nhau.

Joel có một bài viết về điều này:

Tối thiểu tuyệt đối mọi nhà phát triển phần mềm hoàn toàn, tích cực phải biết về Unicode và bộ ký tự (không có lý do gì!)


79
2018-01-23 14:03



"1 ký tự có thể được biểu diễn bằng 1 hoặc nhiều byte" Tôi đồng ý. Tôi chỉ muốn những byte bất kể những gì mã hóa chuỗi là in Cách duy nhất một chuỗi có thể được lưu trữ trong bộ nhớ là trong byte. Ngay cả các ký tự được lưu trữ dưới dạng 1 hoặc nhiều byte. Tôi chỉ muốn có được bàn tay của tôi trên chúng byte. - Agnel Kurian
Bạn không cần mã hóa trừ khi bạn (hoặc người khác) thực sự dự định (s) để thông dịch dữ liệu, thay vì coi nó là "khối byte" chung chung. Đối với những thứ như nén, mã hóa, vv, lo lắng về việc mã hóa là vô nghĩa. Xem câu trả lời của tôicho một cách để làm điều này mà không cần lo lắng về việc mã hóa. - Mehrdad
@Mehrdad - Hoàn toàn, nhưng câu hỏi ban đầu, như đã nói khi tôi trả lời ban đầu, không báo trước những gì OP sẽ xảy ra với những byte đó sau khi họ chuyển đổi chúng, và cho những người tìm kiếm trong tương lai thông tin xung quanh đó là thích hợp - đây là được bao phủ bởi Câu trả lời của Joel khá độc đáo - và khi bạn nêu trong câu trả lời của bạn: miễn là bạn gắn bó trong thế giới .NET và sử dụng các phương thức của bạn để chuyển đổi sang / từ, bạn đang hạnh phúc. Ngay sau khi bạn bước ra khỏi đó, mã hóa sẽ quan trọng. - Zhaph - Ben Duguid


Đây là một câu hỏi phổ biến. Điều quan trọng là phải hiểu những gì tác giả câu hỏi đang hỏi, và nó khác với những gì có thể là nhu cầu phổ biến nhất. Để ngăn chặn việc lạm dụng mã không cần đến, tôi đã trả lời câu hỏi đầu tiên sau.

Nhu cầu chung

Mỗi chuỗi có một bộ ký tự và mã hóa. Khi bạn chuyển đổi System.String đối tượng cho một mảng System.Byte bạn vẫn có một bộ ký tự và mã hóa. Đối với hầu hết các tập quán, bạn sẽ biết bộ ký tự và mã hóa nào bạn cần và .NET làm cho nó đơn giản thành "sao chép với chuyển đổi". Chỉ cần chọn Encoding lớp học.

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

Chuyển đổi có thể cần xử lý các trường hợp bộ ký tự hoặc mã hóa đích không hỗ trợ ký tự nằm trong nguồn. Bạn có một số lựa chọn: ngoại lệ, thay thế hoặc bỏ qua. Chính sách mặc định là thay thế '?'.

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

Rõ ràng, các chuyển đổi không nhất thiết là mất mát!

Lưu ý: Đối với System.String bộ ký tự nguồn là Unicode.

Điều gây nhầm lẫn duy nhất là .NET sử dụng tên của một bộ ký tự cho tên của một mã hóa cụ thể của bộ ký tự đó. Encoding.Unicode nên được gọi là Encoding.UTF16.

Đó là nó cho hầu hết các tập quán. Nếu đó là những gì bạn cần, hãy dừng đọc ở đây. Xem niềm vui Bài viết của Joel Spolsky nếu bạn không hiểu mã hóa là gì.

Nhu cầu cụ thể

Bây giờ, các tác giả câu hỏi hỏi, "Mỗi chuỗi được lưu trữ như là một mảng byte, phải không? Tại sao tôi không thể chỉ đơn giản là có những byte?"

Anh ta không muốn bất kỳ chuyển đổi nào.

Từ C # spec:

Xử lý ký tự và chuỗi trong C # sử dụng mã hóa Unicode. Char   loại đại diện cho đơn vị mã UTF-16 và loại chuỗi đại diện cho   chuỗi các đơn vị mã UTF-16.

Vì vậy, chúng tôi biết rằng nếu chúng tôi yêu cầu chuyển đổi null (nghĩa là, từ UTF-16 sang UTF-16), chúng tôi sẽ nhận được kết quả mong muốn:

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

Nhưng để tránh đề cập đến mã hóa, chúng ta phải làm theo cách khác. Nếu một kiểu dữ liệu trung gian được chấp nhận, có một lối tắt khái niệm cho điều này:

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

Điều đó không nhận được chúng tôi kiểu dữ liệu mong muốn nhưng Câu trả lời của Mehrdad cho thấy cách chuyển đổi mảng Char này thành mảng Byte bằng cách sử dụng BlockCopy. Tuy nhiên, điều này sao chép chuỗi hai lần! Và, nó sử dụng một cách rõ ràng mã mã cụ thể: kiểu dữ liệu System.Char.

Cách duy nhất để nhận được các byte thực tế mà String được lưu trữ là sử dụng một con trỏ. Các fixed tuyên bố cho phép lấy địa chỉ của các giá trị. Từ thông số C #:

[Đối với] một biểu thức của chuỗi kiểu, ... bộ khởi tạo tính toán   địa chỉ của ký tự đầu tiên trong chuỗi.

Để làm như vậy, trình biên dịch viết mã bỏ qua các phần khác của đối tượng chuỗi với RuntimeHelpers.OffsetToStringData. Vì vậy, để có được các byte thô, chỉ cần tạo một con trỏ tới chuỗi và sao chép số byte cần thiết.

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

Như @CodesInChaos chỉ ra, kết quả phụ thuộc vào độ tin cậy của máy. Nhưng tác giả câu hỏi không quan tâm đến điều đó.


76
2017-12-02 04:43



Nói chung, không đúng để đặt byteCount gấp đôi độ dài chuỗi. Đối với các điểm mã Unicode ngoài Mặt phẳng đa ngôn ngữ cơ bản, sẽ có hai đơn vị mã 16 bit cho mỗi ký tự. - Jan Hettich
@Jan Đó là chính xác nhưng chiều dài chuỗi đã cung cấp cho số lượng các đơn vị mã (không codepoints). - Tom Blodget
Cảm ơn bạn đã chỉ ra điều đó! Từ MSDN: "The Length tài sản của String] trả về số lượng Char các đối tượng trong trường hợp này, không phải số ký tự Unicode. "Mã ví dụ của bạn do đó được sửa đúng như văn bản. - Jan Hettich
@TomBlodget: Thật thú vị, nếu có một trường hợp Globalization.SortKey, chiết xuất KeyDatavà gộp các byte kết quả từ mỗi thành một String [hai byte cho mỗi ký tự, MSB trước], đang gọi String.CompareOrdinal khi các chuỗi kết quả sẽ nhanh hơn đáng kể so với gọi SortKey.Compare trên các phiên bản của SortKey, hoặc thậm chí gọi memcmp trên những trường hợp đó. Cho rằng, tôi tự hỏi tại sao KeyData trả về một Byte[] thay vì String? - supercat
@TomBlodget: Bạn không cần fixed hoặc là unsafe mã, bạn cũng có thể làm var gch = GCHandle.Alloc("foo", GCHandleType.Pinned); var arr = new byte[sizeof(char) * ((string)gch.Target).Length]; Marshal.Copy(gch.AddrOfPinnedObject(), arr, 0, arr.Length); gch.Free(); - Mehrdad


Chỉ để chứng minh rằng âm thanh của Mehrdrad câu trả lời hoạt động, cách tiếp cận của anh ấy thậm chí có thể tồn tại ký tự thay thế chưa ghép nối(trong đó nhiều người đã chống lại câu trả lời của tôi, nhưng trong đó mọi người đều có tội, ví dụ System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytes; các phương thức mã hóa đó không thể duy trì các ký tự thay thế cao d800ví dụ, và những người chỉ đơn thuần thay thế các nhân vật thay thế cao bằng giá trị 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);
    }        
}

Đầu ra:

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

Hãy thử với System.Text.Encoding.UTF8.GetBytes hoặc là System.Text.Encoding.Unicode.GetBytes, họ sẽ chỉ thay thế các nhân vật thay thế cao bằng giá trị fffd

Mỗi khi có một chuyển động trong câu hỏi này, tôi vẫn đang nghĩ đến một serializer (có thể là từ Microsoft hoặc từ thành phần của bên thứ 3) có thể tồn tại các chuỗi ngay cả khi nó chứa các ký tự thay thế chưa được ghép nối; Tôi google này mỗi bây giờ và sau đó: serialization unaired ký tự thay thế.. Điều này không làm tôi mất ngủ, nhưng nó hơi khó chịu khi mọi người và sau đó có ai đó bình luận về câu trả lời của tôi rằng nó không hoàn thiện, nhưng câu trả lời của họ cũng thiếu sót khi nói đến các nhân vật thay thế.

Darn, Microsoft nên đã sử dụng System.Buffer.BlockCopy trong nó BinaryFormatter ツ

谢谢!


35
2017-07-25 22:52



Không thay thế phải xuất hiện theo cặp để tạo thành các điểm mã hợp lệ? Nếu là vậy, tôi có thể hiểu tại sao dữ liệu lại bị xáo trộn. - dtanders
@ dtanders Vâng, đó là suy nghĩ của tôi nữa, họ phải xuất hiện theo cặp, các nhân vật thay thế không hợp lệ chỉ xảy ra nếu bạn cố ý đặt chúng vào chuỗi và làm cho chúng bị bỏ ghép. Những gì tôi không biết là lý do tại sao các dev khác tiếp tục bừa bãi rằng chúng ta nên sử dụng cách tiếp cận nhận biết mã hóa thay vào đó, khi họ cho rằng cách tiếp cận tuần tự hóa (câu trả lời của tôi, đó là một câu trả lời được chấp nhận trong hơn 3 năm) không giữ nguyên nhân vật thay thế bị bỏ rơi. Nhưng họ quên kiểm tra rằng các giải pháp nhận biết mã hóa của họ cũng không giữ cho nhân vật thay thế chưa được ghép nối, sự mỉa mai ツ - Michael Buen
Nếu có thư viện tuần tự hóa sử dụng System.Buffer.BlockCopy trong nội bộ, tất cả các đối số của những người ủng hộ mã hóa sẽ là tranh luận - Michael Buen
Vấn đề với thử nghiệm của bạn là bạn đã tạo một chuỗi không hợp lệ. "Trong UTF-16, chúng phải luôn luôn xuất hiện theo cặp, như là một đại diện thay thế bởi một đại diện thay thế thấp, do đó sử dụng 32 bit để biểu thị một điểm mã.". Nếu bạn làm theo / uD800 với / uDC00 thì nó hoạt động tốt trong tất cả các định dạng unicode. Điều quan trọng cần lưu ý rằng đây là một chuỗi, không phải là một mảng char, do đó, một số hạn chế có ý nghĩa. Ngoài ra, nó hoạt động tốt ngay cả khi không có / uDC00 trong UTF7. - Trisped
@dtanders: A System.String là một chuỗi bất biến của Char; .NET luôn cho phép String đối tượng được xây dựng từ bất kỳ Char[] và xuất nội dung của nó sang Char[] chứa các giá trị giống nhau, ngay cả khi ban đầu Char[] chứa người đại diện chưa được kết nối. - supercat


Hãy thử điều này, ít hơn rất nhiều mã:

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

34
2018-01-23 15:54



Sau đó thử cái này System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);, và khóc! Nó sẽ hoạt động, nhưng System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Length trong khi "Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length - mg30rg
@ mg30rg: Tại sao bạn nghĩ rằng ví dụ của bạn là lạ? Chắc chắn trong một bảng mã có độ rộng biến không phải tất cả các ký tự đều có cùng độ dài byte. Có gì sai với nó? - Vlad


Phần đầu tiên của câu hỏi của bạn (cách nhận các byte) đã được trả lời bởi những người khác: xem trong System.Text.Encoding không gian tên.

Tôi sẽ giải quyết câu hỏi tiếp theo của bạn: tại sao bạn cần chọn mã hóa? Tại sao bạn không thể lấy nó từ chính lớp chuỗi?

Câu trả lời là hai phần.

Đầu tiên, các byte được sử dụng nội bộ bởi lớp chuỗi không quan trọngvà bất cứ khi nào bạn cho rằng họ có khả năng sẽ giới thiệu một lỗi.

Nếu chương trình của bạn hoàn toàn nằm trong thế giới .Net thì bạn không cần phải lo lắng về việc nhận mảng byte cho tất cả các chuỗi, ngay cả khi bạn đang gửi dữ liệu qua mạng. Thay vào đó, hãy sử dụng. Serialization để lo lắng về việc truyền dữ liệu. Bạn không phải lo lắng về các byte thực tế nữa: định dạng tuần tự hóa sẽ làm điều đó cho bạn.

Mặt khác, điều gì sẽ xảy ra nếu bạn gửi các byte này đến đâu đó mà bạn không thể đảm bảo sẽ lấy dữ liệu từ một luồng tuần tự .Net? Trong trường hợp này bạn chắc chắn cần phải lo lắng về mã hóa, bởi vì rõ ràng hệ thống bên ngoài này quan tâm. Vì vậy, một lần nữa, các byte nội bộ được sử dụng bởi chuỗi không quan trọng: bạn cần phải chọn một mã hóa để bạn có thể rõ ràng về mã hóa này trên đầu nhận, ngay cả khi đó là cùng một mã hóa được sử dụng nội bộ bởi .Net.

Tôi hiểu rằng trong trường hợp này, bạn có thể thích sử dụng các byte thực được lưu trữ bởi biến chuỗi trong bộ nhớ nếu có thể, với ý tưởng rằng nó có thể tiết kiệm một số công việc tạo luồng byte của bạn. Tuy nhiên, tôi đặt nó cho bạn nó chỉ là không quan trọng so với việc đảm bảo rằng đầu ra của bạn được hiểu ở đầu kia, và để đảm bảo rằng bạn phải rõ ràng với mã hóa của bạn. Ngoài ra, nếu bạn thực sự muốn so khớp các byte nội bộ của mình, bạn có thể đã chọn Unicode mã hóa và nhận được hiệu suất tiết kiệm đó.

Điều đó đưa tôi đến phần thứ hai ... chọn Unicode mã hóa  nói. Net để sử dụng các byte cơ bản. Bạn cần phải chọn mã hóa này, bởi vì khi một số Unicode-Plus mới bị vướng víu xuất hiện, thời gian chạy Net cần phải được miễn phí để sử dụng mô hình mã hóa mới hơn, tốt hơn này mà không phá vỡ chương trình của bạn. Tuy nhiên, trong thời điểm này (và tương lai thuận lợi), chỉ cần chọn mã hóa Unicode sẽ cung cấp cho bạn những gì bạn muốn.

Điều quan trọng là phải hiểu chuỗi của bạn phải được viết lại thành dây và điều đó liên quan đến ít nhất một số bản dịch của mẫu bit ngay cả khi bạn sử dụng mã hóa phù hợp. Máy tính cần tính đến những thứ như Big vs Little Endian, thứ tự byte mạng, đóng gói, thông tin phiên, v.v.


34
2018-03-10 08:57



Có các vùng trong .NET, nơi bạn phải nhận mảng byte cho chuỗi. Nhiều lớp .NET Cryptrography chứa các phương thức như ComputeHash () chấp nhận mảng hoặc luồng byte. Bạn không có cách nào khác ngoài việc chuyển đổi một chuỗi thành một mảng byte trước tiên (chọn một Mã hóa) và sau đó tùy chọn bọc nó trong một luồng. Tuy nhiên, miễn là bạn chọn một mã hóa (tức là UTF8) một thanh với nó không có vấn đề với điều này. - Ash