C # แปลงสตริงจาก UTF-8 เป็น ISO-8859-1 (Latin1) H


104

ฉันได้เข้าสู่หัวข้อนี้และได้ดูทุกคำตอบแล้ว แต่ก็ยังไม่เข้าใจ

โดยทั่วไปฉันต้องแปลงสตริง UTF-8 เป็น ISO-8859-1 และทำโดยใช้รหัสต่อไปนี้:

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

สตริงต้นทางของฉันคือ

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

แต่น่าเสียดายที่สตริงผลลัพธ์ของฉันกลายเป็น

msg = "�ä�ö�õ�ü

ฉันทำอะไรผิดที่นี่?


5
สตริงทั้งหมดใน. NET เก็บสตริงไว้ภายในโดยใช้อักขระ Unicode ไม่มีความคิดของสตริงที่เป็น "windows-1252", "iso-8859-1", "utf-8" ฯลฯ คุณกำลังพยายามทิ้งอักขระใด ๆ ในสตริงของคุณที่ไม่มีการแสดงใน Windows -1252 หน้ารหัส?
Ian Boyd

1
@IanBoyd จริงๆแล้วStringคือลำดับการนับของหน่วยรหัส UTF-16 (ขออภัยคำว่า Unicode ถูกนำไปใช้อย่างไม่ถูกต้องEncoding.Unicodeและใน Win32 API Unicode คือชุดอักขระไม่ใช่การเข้ารหัส UTF-16 เป็นหนึ่งในการเข้ารหัสหลายรายการสำหรับ Unicode)
Tom Blodget

1
คุณดำเนินการไม่ถูกต้อง: คุณสร้างไบต์อาร์เรย์ในการเข้ารหัส utf8 แต่อ่านโดยการถอดรหัส iso หากคุณต้องการสร้างสตริงด้วยสัญลักษณ์ที่เข้ารหัสให้เรียกสตริงที่
StuS

ที่เรียกว่า Mojibake
Rick James

ฉันเดาว่า Daniil พูดว่าอะไรคือMessageถอดรหัสจาก UTF-8 สมมติว่าส่วนนั้นทำงานได้อย่างถูกต้องการแปลงเป็นภาษาละติน -1 นั้นง่ายพอbyte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message)ๆ จากนั้นเช่นเดียวกับที่ StuS กล่าวว่าคุณสามารถแปลง Latin-1 ไบต์กลับไปเป็น UTF-16 ด้วยEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

คำตอบ:


177

ใช้Encoding.Convertเพื่อปรับไบต์อาร์เรย์ก่อนที่จะพยายามถอดรหัสเป็นการเข้ารหัสปลายทางของคุณ

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
ซับเดียวคือEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))

1
หากคุณสร้างสตริงด้วยตัวเองภายใน C # /. net แสดงว่ารหัสนี้ไม่ถูกต้อง 100% คุณต้องเข้ารหัสจาก UTF-16 (ซึ่งก็คือตัวแปร "Unicode") เพราะนี่คือค่าเริ่มต้น ดังนั้น UTF8 ในโค้ดด้านบนจึงต้องเปลี่ยนเป็น Unicode
goamn

ฉันแนะนำให้ใช้สิ่งนี้: การเข้ารหัส iso = Encoding.GetEncoding ("ISO-8859-9"); เนื่องจากการเข้ารหัสภาษาตุรกีครอบคลุมตัวอักษรเกือบทั้งหมดที่ขยายมาจากภาษาละติน
Fuat

27

ฉันคิดว่าปัญหาของคุณคือคุณคิดว่าไบต์ที่แสดงสตริง utf8 จะทำให้เกิดสตริงเดียวกันเมื่อตีความเป็นอย่างอื่น (iso-8859-1) และนั่นไม่ใช่แค่กรณี ฉันแนะนำให้คุณอ่านบทความที่ยอดเยี่ยมนี้โดย Joel spolsky


1
บทความที่ยอดเยี่ยมและมีอารมณ์ขัน! วันนี้ฉันประสบปัญหาการเข้ารหัสในที่ทำงานและสิ่งนี้ช่วยฉันได้
Pantelis

16

ลองสิ่งนี้:

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

ทำไมฉันถึงได้รับข้อความ utf-8 เดียวกันแทนข้อความที่ฉันส่ง string message = <name> sdjfhsjdf </name> ผลลัพธ์เดียวกันจึงได้รับใน msg varieable วิธีรับข้อมูลละติน
user1237131

สิ่งนี้ใช้ได้กับฉัน อย่าลืมรวมเนมสเปซ System.Text
Spawnrider

2
การเข้ารหัสแปลงจะแสดงข้อยกเว้นทางเลือกในขณะที่แปลงหากสตริงมีอักขระที่ไม่ใช่ iso
Tertium

8

คุณต้องแก้ไขแหล่งที่มาของสตริงตั้งแต่แรก

สตริงใน. NET เป็นเพียงอาร์เรย์ของรหัส Unicode 16 บิตอักขระดังนั้นสตริงจึงไม่ได้อยู่ในการเข้ารหัสใด ๆ

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

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

คุณช่วยบอกเราเพิ่มเติมได้ไหมว่าสตริงต้นฉบับนั้นมาจากไหนและทำไมคุณถึงคิดว่ามันถูกเข้ารหัสผิด


มันมาจาก App.config โดยตรงและฉันคิดว่ามันเป็น UTF8 โดยค่าเริ่มต้น ขอบคุณ!
Daniil Harik

การเข้ารหัสของไฟล์นั้นอาจส่งผลต่อวิธีการตีความไฟล์ดังนั้นฉันจะดูว่า
Lasse V.Karlsen

2
แก้ไขฉันถ้าฉันผิด แต่ความเข้าใจของฉันคือในขณะที่ในทางเทคนิคมัน "ไม่ได้อยู่ในการเข้ารหัสใด ๆ " สตริง. NET เป็นอาร์เรย์ไบต์ที่ตรงกับไฟล์ UTF-16 อย่างแม่นยำโดยเป็นไบต์สำหรับไบต์ (ไม่รวม BOM) มันยังใช้ตัวแทนในลักษณะเดียวกัน (ซึ่งดูเหมือนเป็นเคล็ดลับการเข้ารหัส) แน่นอนโดยทั่วไปคุณต้องการจัดเก็บไฟล์เป็น UTF-8 แต่ประมวลผลข้อมูลในหน่วยความจำเป็น 16 บิต (หรือ 32 บิตเพื่อหลีกเลี่ยงความซับซ้อนของคู่ตัวแทนแม้ว่าฉันไม่แน่ใจว่าเป็นไปได้จริงหรือไม่)
จอนคูมบ์ส

6

ดูเหมือนรหัสแปลก ๆ ในการรับสตริงจากสตรีม Utf8 byte สิ่งที่คุณต้องทำคือ:

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

หากคุณต้องการบันทึก iso-8859-1 ไบต์สตรีมไปที่ใดที่หนึ่งให้ใช้: บรรทัดรหัสเพิ่มเติมสำหรับก่อนหน้านี้:

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

1
นี่คือคำตอบที่ตรงไปตรงมาอย่างชัดเจนที่สุด ปัญหาในโค้ดคือผู้เขียนคิดว่า String ใน C # สามารถจัดเก็บได้แล้ว "โดยใช้" การเข้ารหัสบางอย่างซึ่งไม่เป็นความจริง พวกเขามักจะ UTF16 ภายใน
Nyerguds

1
เห็นด้วยอย่างเต็มที่. เมื่อคุณมี UTF-16 อยู่แล้วการเข้ารหัสที่ถูกต้องนั้นค่อนข้างยากเพราะเมื่อคุณแปลงไบต์อาร์เรย์เป็นสตริงด้วยการเข้ารหัสที่ไม่ถูกต้องข้อมูลจะสูญหายไปแล้ว
Sander A

0

เพิ่งใช้วิธีแก้ปัญหาของนาธานและใช้งานได้ดี ฉันต้องการแปลง ISO-8859-1 เป็น 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

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