C # Convertir la chaîne de UTF-8 en ISO-8859-1 (Latin1) H

103

J'ai cherché sur Google ce sujet et j'ai examiné toutes les réponses, mais je ne comprends toujours pas.

Fondamentalement, je dois convertir la chaîne UTF-8 en ISO-8859-1 et je le fais en utilisant le code suivant:

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

Ma chaîne source est

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

Mais malheureusement, ma chaîne de résultat devient

msg = "�ä�ö�õ�ü

Qu'est-ce que je fais de mal ici?

Daniil Harik
la source
5
Toutes les chaînes de .NET stockent en interne les chaînes à l'aide de caractères Unicode. Il n'y a aucune notion d'une chaîne étant "windows-1252", "iso-8859-1", "utf-8", etc. Essayez-vous de jeter tous les caractères de votre chaîne qui n'ont pas de représentation dans Windows -1252 page de codes?
Ian Boyd
1
@IanBoyd En fait, une chaîne est une séquence comptée d'unités de code UTF-16. (Malheureusement, le terme Unicode a été mal appliqué dans Encoding.Unicodeet dans l'API Win32. Unicode est un jeu de caractères, pas un encodage. UTF-16 est l'un des nombreux encodages pour Unicode.)
Tom Blodget
1
Vous faites une action incorrecte: vous créez un tableau d'octets en encodage utf8, mais vous les lisez par décodage iso. Si vous voulez créer une chaîne avec des symboles encodés, appelez simplement la chaîne msg = iso.GetString (iso.GetBytes (Message));
StuS
Cela s'appelle Mojibake.
Rick James
Je suppose que ce que dit Daniil, c'est qu'il a Messageété décodé à partir de l'UTF-8. En supposant que cette partie fonctionne correctement, la conversion en Latin-1 est aussi simple que byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Ensuite, comme le dit StuS, vous pouvez reconvertir les octets Latin-1 en UTF-16 avecEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

Réponses:

176

Utilisez Encoding.Convert pour ajuster le tableau d'octets avant d'essayer de le décoder dans votre encodage de destination.

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);
Nathan Baulch
la source
7
The one liner isEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))
1
Si vous créez la chaîne vous-même dans C # /. Net, alors ce code n'est pas correct à 100%, vous devez encoder à partir de UTF-16 (qui est la variable "Unicode"). Parce que c'est la valeur par défaut. Donc UTF8 dans le code ci-dessus doit être changé en Unicode.
goamn
Je recommande d'utiliser ceci: Encoding iso = Encoding.GetEncoding ("ISO-8859-9"); Parce que l'encodage turc couvre presque tout l'alphabet étendu du latin.
Fuat
26

Je pense que votre problème est que vous supposez que les octets qui représentent la chaîne utf8 donneront la même chaîne lorsqu'ils seront interprétés comme autre chose (iso-8859-1). Et ce n'est tout simplement pas le cas. Je vous recommande de lire cet excellent article de Joel spolsky.

Klaus Byskov Pedersen
la source
1
Excellent article en effet et avec un sens de l'humour! J'étais confronté à un problème d'encodage aujourd'hui au travail et cela m'a aidé.
Pantelis
16

Essaye ça:

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);
Manu
la source
pourquoi je reçois le même message utf-8? à la place du message, j'ai passé la chaîne message = <nom> sdjfhsjdf </name> .puis même sortie obtenant dans msg varieable.how pour obtenir des données latines?
user1237131
Cela fonctionne pour moi. N'oubliez pas d'inclure l'espace de noms System.Text.
Spawnrider
2
Encoding.Convert lève une exception de repli lors de la conversion si la chaîne contient des caractères non iso
Tertium
8

Vous devez d'abord corriger la source de la chaîne.

Une chaîne dans .NET est en fait juste un tableau de points de code Unicode 16 bits, de caractères, donc une chaîne n'est pas dans un codage particulier.

C'est lorsque vous prenez cette chaîne et la convertissez en un ensemble d'octets que l'encodage entre en jeu.

Dans tous les cas, la façon dont vous l'avez fait, encodé une chaîne dans un tableau d'octets avec un jeu de caractères, puis le décodage avec un autre, ne fonctionnera pas, comme vous le voyez.

Pouvez-vous nous en dire plus sur l'origine de cette chaîne d'origine et pourquoi vous pensez qu'elle a été mal encodée?

Lasse V. Karlsen
la source
Cela vient directement d'App.config et je pensais que c'était UTF8 par défaut. Merci!
Daniil Harik
L'encodage de ce fichier peut avoir un impact sur la façon dont le fichier est interprété, alors je regarderais cela.
Lasse V. Karlsen
2
Corrigez-moi si je me trompe, mais je crois comprendre que, bien que techniquement ce ne soit "aucun encodage particulier", une chaîne .NET est un tableau d'octets qui correspond précisément à un fichier UTF-16, octet pour octet (à l'exclusion la nomenclature). Il utilise même des substituts de la même manière (ce qui semble être une astuce d'encodage). Bien sûr, vous souhaitez généralement stocker des fichiers au format UTF-8, mais traiter les données en mémoire en 16 bits. (Ou 32 bits, pour éviter la complexité des paires de substitution, même si je ne suis pas sûr que ce soit vraiment faisable.)
Jon Coombs
6

Cela semble un peu étrange. Pour obtenir une chaîne à partir du flux d'octets Utf8, tout ce que vous devez faire est:

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

Si vous devez enregistrer le flux d'octets iso-8859-1 quelque part, utilisez simplement: ligne de code supplémentaire pour la précédente:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);
Ponceuse A
la source
1
C'est clairement la réponse la plus simple. Le problème dans le code est en effet que l'auteur semble supposer qu'une chaîne en C # peut déjà être stockée "en utilisant" un certain codage, ce qui n'est tout simplement pas vrai; ils sont toujours UTF16 en interne.
Nyerguds
1
Entièrement d'accord. Lorsque vous avez déjà UTF-16, il est assez difficile d'en faire un encodage correct, car lorsque vous convertissez un tableau d'octets en chaîne avec un encodage incorrect, il y a déjà une perte d'informations.
Sander A
0

Je viens d'utiliser la solution de Nathan et cela fonctionne très bien. J'avais besoin de convertir ISO-8859-1 en 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);
Nicolai Nita
la source
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);
Tomáš Opis
la source
-5

Voici un exemple pour 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 = "[email protected]";
    SmtpClient client = new SmtpClient("mail.xxxxx.org");
    MailMessage message = new MailMessage(Email, "[email protected]", "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);}
Moteur Kamarot
la source