C # Chuyển đổi chuỗi từ UTF-8 sang ISO-8859-1 (Latin1) H


103

Tôi đã tìm kiếm trên Google về chủ đề này và tôi đã xem xét mọi câu trả lời, nhưng tôi vẫn không hiểu.

Về cơ bản, tôi cần chuyển đổi chuỗi UTF-8 thành ISO-8859-1 và tôi làm điều đó bằng cách sử dụng mã sau:

Encoding iso = Encoding.GetEncoding("ISO-8859-1");
Encoding utf8 = Encoding.UTF8;
string msg = iso.GetString(utf8.GetBytes(Message));

Chuỗi nguồn của tôi là

Message = "ÄäÖöÕõÜü"

Nhưng tiếc là chuỗi kết quả của tôi trở thành

msg = "�ä�ö�õ�ü

Tôi đang làm gì sai ở đây?


5
Tất cả các chuỗi trong .NET lưu trữ nội bộ các chuỗi bằng cách sử dụng các ký tự unicode. Không có khái niệm về một Chuỗi là "windows-1252", "iso-8859-1", "utf-8", v.v. Bạn đang cố gắng loại bỏ bất kỳ ký tự nào trong chuỗi của mình mà không có đại diện trong Windows -1252 trang mã?
Ian Boyd

1
@IanBoyd Trên thực tế, một Chuỗi là một chuỗi được đếm của các đơn vị mã UTF-16. (Thật không may, Unicode hạn đã được áp dụng sai trong Encoding.Unicodevà trong API Win32 Unicode là một bộ ký tự, không phải là một mã hóa UTF-16 là một trong những mã hóa cho Unicode...)
Tom Blodget

1
Bạn thực hiện hành động không chính xác: bạn tạo mảng byte trong mã hóa utf8, nhưng đọc chúng bằng giải mã iso. Nếu bạn muốn tạo chuỗi với các ký hiệu được mã hóa, nó đơn giản gọi chuỗi msg = iso.GetString (iso.GetBytes (Message));
StuS

Đó được gọi là Mojibake.
Rick James

Tôi đoán những gì Daniil đang nói là Messageđược giải mã từ UTF-8. Giả sử phần đó hoạt động chính xác, việc chuyển đổi sang Latin-1 cũng đơn giản như vậy byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Sau đó, giống như StuS nói, bạn có thể chuyển đổi các byte Latin-1 sao sang UTF-16 vớiEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

Câu trả lời:


176

Sử dụng Encoding.Convert để điều chỉnh mảng byte trước khi cố gắng giải mã nó thành mã hóa đích của bạn.

Encoding iso = Encoding.GetEncoding("ISO-8859-1");
Encoding utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(Message);
byte[] isoBytes = Encoding.Convert(utf8, iso, utfBytes);
string msg = iso.GetString(isoBytes);

7
Một liner làEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))

1
Nếu bạn đang tự tạo chuỗi bên trong C # /. Net, thì mã này không đúng 100%, bạn cần mã hóa từ UTF-16 (là biến "Unicode"). Vì đây là mặc định. Vì vậy UTF8 trong đoạn mã trên phải được đổi thành Unicode.
goamn

Tôi khuyên bạn nên sử dụng cái này: Encoding iso = Encoding.GetEncoding ("ISO-8859-9"); Bởi vì mã hóa tiếng Thổ Nhĩ Kỳ bao gồm hầu hết tất cả các bảng chữ cái mở rộng từ tiếng Latinh.
Fuat,

26

Tôi nghĩ rằng vấn đề của bạn là bạn giả định rằng các byte đại diện cho chuỗi utf8 sẽ dẫn đến cùng một chuỗi khi được hiểu là một cái gì đó khác (iso-8859-1). Và đó chỉ đơn giản là không phải như vậy. Tôi khuyên bạn nên đọc bài viết xuất sắc này của Joel spolsky.


1
Bài báo xuất sắc thực sự và với một cảm giác hài hước! Tôi đã gặp phải sự cố mã hóa ngày hôm nay tại nơi làm việc và điều này đã giúp tôi giải quyết.
Pantelis

16

Thử cái này:

Encoding iso = Encoding.GetEncoding("ISO-8859-1");
Encoding utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(Message);
byte[] isoBytes = Encoding.Convert(utf8,iso,utfBytes);
string msg = iso.GetString(isoBytes);

tại sao tôi nhận được cùng một thông báo utf-8? thay cho thông báo tôi đã chuyển chuỗi message = <name> sdjfhsjdf </name>. sau đó cùng một đầu ra nhận được trong msg biến thể. làm thế nào để nhận dữ liệu latin?
user1237131

Điều này làm việc cho tôi. Hãy nhớ bao gồm không gian tên System.Text.
Spawnrider

2
Encoding.Convert ném ngoại lệ dự phòng trong khi chuyển đổi nếu chuỗi có các ký tự không phải iso
Tertium

8

Bạn cần phải sửa nguồn của chuỗi ngay từ đầu.

Một chuỗi trong .NET thực chất chỉ là một mảng gồm các ký tự, điểm mã unicode 16 bit, vì vậy một chuỗi không nằm trong bất kỳ bảng mã cụ thể nào.

Đó là khi bạn lấy chuỗi đó và chuyển đổi nó thành một tập hợp các byte, mã hóa sẽ phát huy tác dụng.

Trong mọi trường hợp, cách bạn đã làm, mã hóa một chuỗi thành một mảng byte với một bộ ký tự và sau đó giải mã nó bằng một bộ ký tự khác, sẽ không hoạt động, như bạn thấy.

Bạn có thể cho chúng tôi biết thêm về chuỗi gốc đó đến từ đâu và tại sao bạn nghĩ rằng nó đã được mã hóa sai?


Nó đến trực tiếp từ App.config và tôi nghĩ nó là UTF8 theo mặc định. Cảm ơn bạn!
Daniil Harik

Việc mã hóa tệp đó có thể ảnh hưởng đến cách tệp được diễn giải, vì vậy tôi sẽ xem xét điều đó.
Lasse V. Karlsen

2
Hãy sửa cho tôi nếu tôi sai, nhưng sự hiểu biết của tôi là, mặc dù về mặt kỹ thuật nó "không có trong bất kỳ mã hóa cụ thể nào", chuỗi .NET là một mảng byte tương ứng chính xác với tệp UTF-16, byte cho byte (loại trừ BOM). Nó thậm chí còn sử dụng các đại diện theo cách tương tự (có vẻ giống như một thủ thuật mã hóa). Tất nhiên, bạn thường muốn lưu trữ tệp dưới dạng UTF-8 nhưng xử lý dữ liệu trong bộ nhớ dưới dạng 16 bit. (Hoặc 32-bit, để tránh sự phức tạp của cặp thay thế, mặc dù tôi không chắc chắn nếu đó là thực sự khả thi.)
Jon Coombs

6

Có vẻ như mã hơi lạ. Để lấy chuỗi từ luồng byte Utf8, tất cả những gì bạn cần làm là:

string str = Encoding.UTF8.GetString(utf8ByteArray);

Nếu bạn cần lưu luồng byte iso-8859-1 vào một nơi nào đó thì chỉ cần sử dụng: dòng mã bổ sung cho trước:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);

1
Đây rõ ràng là câu trả lời đơn giản nhất. Vấn đề trong mã thực sự là tác giả dường như giả định rằng một Chuỗi trong C # đã có thể được lưu trữ "bằng cách sử dụng" một mã hóa nhất định, điều này đơn giản là không đúng; chúng luôn luôn là UTF16 nội bộ.
Nyerguds

1
Hoàn toàn đồng ý. Khi bạn đã có UTF-16, rất khó để biến điều đó thành mã hóa chính xác, bởi vì khi bạn chuyển đổi mảng byte thành chuỗi với mã hóa sai thì sẽ mất thông tin.
Sander A

0

Chỉ cần sử dụng giải pháp của Nathan và nó hoạt động tốt. Tôi cần chuyển đổi ISO-8859-1 sang Unicode:

string isocontent = Encoding.GetEncoding("ISO-8859-1").GetString(fileContent, 0, fileContent.Length);
byte[] isobytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(isocontent);
byte[] ubytes = Encoding.Convert(Encoding.GetEncoding("ISO-8859-1"), Encoding.Unicode, isobytes);
return Encoding.Unicode.GetString(ubytes, 0, ubytes.Length);

0
Encoding targetEncoding = Encoding.GetEncoding(1252);
// Encode a string into an array of bytes.
Byte[] encodedBytes = targetEncoding.GetBytes(utfString);
// Show the encoded byte values.
Console.WriteLine("Encoded bytes: " + BitConverter.ToString(encodedBytes));
// Decode the byte array back to a string.
String decodedString = Encoding.Default.GetString(encodedBytes);

-5

Đây là một mẫu cho ISO-8859-9;

protected void btnKaydet_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.Buffer = true;
    Response.ContentType = "application/vnd.openxmlformatsofficedocument.wordprocessingml.documet";
    Response.AddHeader("Content-Disposition", "attachment; filename=XXXX.doc");
    Response.ContentEncoding = Encoding.GetEncoding("ISO-8859-9");
    Response.Charset = "ISO-8859-9";
    EnableViewState = false;


    StringWriter writer = new StringWriter();
    HtmlTextWriter html = new HtmlTextWriter(writer);
    form1.RenderControl(html);


    byte[] bytesInStream = Encoding.GetEncoding("iso-8859-9").GetBytes(writer.ToString());
    MemoryStream memoryStream = new MemoryStream(bytesInStream);


    string msgBody = "";
    string Email = "mail@xxxxxx.org";
    SmtpClient client = new SmtpClient("mail.xxxxx.org");
    MailMessage message = new MailMessage(Email, "mail@someone.com", "ONLINE APP FORM WITH WORD DOC", msgBody);
    Attachment att = new Attachment(memoryStream, "XXXX.doc", "application/vnd.openxmlformatsofficedocument.wordprocessingml.documet");
    message.Attachments.Add(att);
    message.BodyEncoding = System.Text.Encoding.UTF8;
    message.IsBodyHtml = true;
    client.Send(message);}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.