Comment puis-je transformer une chaîne en UTF-8 en C #?

146

J'ai une chaîne que je reçois d'une application tierce et je souhaite l'afficher correctement dans n'importe quelle langue en utilisant C # sur ma Surface Windows.

En raison d'un encodage incorrect, un morceau de ma chaîne ressemble à ceci en espagnol:

Acción

alors que cela devrait ressembler à ceci:

Acción

Selon la réponse à cette question: Comment connaître l'encodage de chaîne en C # , l'encodage que je reçois devrait déjà arriver sur UTF-8, mais il est lu sur Encoding.Default (probablement ANSI?).

J'essaie de transformer cette chaîne en véritable UTF-8, mais l'un des problèmes est que je ne peux voir qu'un sous-ensemble de la classe Encoding (propriétés UTF8 et Unicode uniquement), probablement parce que je suis limité à l'API de surface Windows.

J'ai essayé quelques extraits que j'ai trouvés sur Internet, mais aucun d'entre eux n'a réussi jusqu'à présent pour les langues orientales (c'est-à-dire le coréen). Un exemple est le suivant:

var utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(myString);
myString= utf8.GetString(utfBytes, 0, utfBytes.Length);     

J'ai également essayé d'extraire la chaîne dans un tableau d'octets, puis d'utiliser UTF8.GetString:

byte[] myByteArray = new byte[myString.Length];
for (int ix = 0; ix < myString.Length; ++ix)
{
    char ch = myString[ix];
    myByteArray[ix] = (byte) ch;
}

myString = Encoding.UTF8.GetString(myByteArray, 0, myString.Length);

Avez-vous d'autres idées que je pourrais essayer?

Gaara
la source
5
Votre problème vient du code qui a créé la chaîne (à partir d'un flux ou d'un octet []) en premier lieu. Veuillez montrer ce code.
SLaks
1
@Oded: les chaînes .Net sont stockées en mémoire au format UTF16, mais Encoding.Defaultretourne la page de codes ANSI du système.
SLaks
Voici un exemple de chaîne qui ne fonctionne pas en anglais: au lieu d'afficher le jour, mon application frontale affiche: dayâ € ™ s
Gaara

Réponses:

251

Comme vous le savez, la chaîne arrive, Encoding.Defaultvous pouvez simplement utiliser:

byte[] bytes = Encoding.Default.GetBytes(myString);
myString = Encoding.UTF8.GetString(bytes);

Une autre chose dont vous devrez peut-être vous souvenir: si vous utilisez Console.WriteLine pour générer des chaînes, vous devez également écrire Console.OutputEncoding = System.Text.Encoding.UTF8;!!! Ou toutes les chaînes utf8 seront affichées en tant que gbk ...

anotherhrubery
la source
Cela fonctionne aussi c'est en fait beaucoup plus gentil que ma réponse qui fonctionne aussi Je vous donne un beau travail +1
MethodMan
Merci! Le problème est que, comme je l'ai mentionné dans la description, l'API de surface est incomplète (pas d'encodage par défaut disponible pour moi).
Gaara
3
@Gaara: Essayez Encoding.GetEncoding(...); vous devrez trouver le nom du codage réel qui a été incorrectement utilisé à l'autre extrémité.
SLaks
1
pouvez-vous expliquer pourquoi cela fonctionne? si la valeur par défaut est GB2312, alors Encoding.Default.GetBytes encodera une chaîne à un tableau d'octets utiliser l'encodeur GB2312, puis Encoding.UTF8.GetString tentera de décoder le tableau d'octets utiliser le décodeur UTF8, le résultat devrait être faux, mais pourquoi cela fonctionne. @anothershrubery
guorongfei
1
@guorongfei La prémisse est que myStringc'est mojibake. Le code annule d'abord le mauvais décodage puis effectue le bon décodage. Cela fonctionne tant que le mauvais décodage n'a pas perdu de données. Mais comme @SLaks l'a souligné, il serait préférable d'utiliser l'encodage exact qui était erroné. (De meilleurs noms et commentaires dans le code aideraient à comprendre à quel point un code très faux est en fait une tentative de bien faire.)
Tom Blodget
18
string utf8String = "Acción";
string propEncodeString = string.Empty;

byte[] utf8_Bytes = new byte[utf8String.Length];
for (int i = 0; i < utf8String.Length; ++i)
{
   utf8_Bytes[i] = (byte)utf8String[i];
}

propEncodeString = Encoding.UTF8.GetString(utf8_Bytes, 0, utf8_Bytes.Length);

La sortie doit ressembler à

Acción

jour affiche le jour

appelez DecodeFromUtf8 ();

private static void DecodeFromUtf8()
{
    string utf8_String = "day’s";
    byte[] bytes = Encoding.Default.GetBytes(utf8_String);
    utf8_String = Encoding.UTF8.GetString(bytes);
}
MethodMan
la source
1
Merci! Cela fonctionne en espagnol, le problème est que la même chose ne fonctionnerait pas sur les langues orientales (c'est-à-dire coréen). J'essaie de rechercher un algorithme de conversion 8 bits en UTF-8 sur Internet, mais toujours pas de chance.
Gaara
Voici un exemple de chaîne qui ne fonctionne pas en anglais: au lieu d'afficher le jour, mon application frontale affiche: dayâ € ™ s
Gaara
ok laissez-moi jouer avec et voir ce que je peux trouver
MethodMan
J'ai testé et il renvoie le jour.Je vais coller la méthode statique que j'ai testée, c'est en fait la même que celle fournie par
@anothershrubery
vous pouvez modifier cette méthode en passant DecodeFromUtf8 (string utf8string);
MethodMan
12

Votre code lit une séquence d'octets encodés en UTF8 et les décode à l'aide d'un encodage 8 bits.

Vous devez corriger ce code pour décoder les octets en UTF8.

Sinon ( pas idéal ), vous pouvez reconvertir la chaîne incorrecte dans le tableau d'octets d'origine - en l'encodant à l'aide d'un encodage incorrect - puis décoder à nouveau les octets en UTF8.

SLaks
la source
Merci! Le problème est que l'application tierce est C ++, tandis que mon code est C #, donc je suppose que le décodage se produit dans le "pont" entre ces deux.
Gaara
8
 Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(mystring));
Riadh Hammouda
la source
5

Si vous souhaitez enregistrer une chaîne dans la base de données mysql, procédez comme suit: ->

La structure des champs de votre base de données i phpmyadmin [ou tout autre panneau de configuration] doit être définie sur utf8-gerneral-ci

2) vous devez changer votre chaîne [Ex. textbox1.text] en octet, par conséquent

2-1) définir l'octet [] st2;

2-2) Convertissez votre chaîne [textbox1.text] en unicode [mmultibyte string] en:

byte[] st2 = System.Text.Encoding.UTF8.GetBytes(textBox1.Text);

3) exécutez cette commande sql avant toute requête:

string mysql_query2 = "SET NAMES 'utf8'";
cmd.CommandText = mysql_query2;
cmd.ExecuteNonQuery();

3-2) maintenant, vous devez insérer cette valeur dans le champ de nom par exemple en:

cmd.CommandText = "INSERT INTO customer (`name`) values (@name)";

4) le travail principal que beaucoup de solutions n'ont pas pris en compte est la ligne ci-dessous: vous devez utiliser addwithvalue au lieu d'ajouter un paramètre de commande comme ci-dessous:

cmd.Parameters.AddWithValue("@name",ut);

+++++++++++++++++++++++++++++++++ Profitez de données réelles dans votre serveur de base de données au lieu de ????

Hassan Fadaie Ghotbie
la source
3

Utilisez l'extrait de code ci-dessous pour obtenir des octets à partir du fichier csv

protected byte[] GetCSVFileContent(string fileName)
    {
        StringBuilder sb = new StringBuilder();
        using (StreamReader sr = new StreamReader(fileName, Encoding.Default, true))
        {
            String line;
            // Read and display lines from the file until the end of 
            // the file is reached.
            while ((line = sr.ReadLine()) != null)
            {
                sb.AppendLine(line);
            }
        }
        string allines = sb.ToString();


        UTF8Encoding utf8 = new UTF8Encoding();


        var preamble = utf8.GetPreamble();

        var data = utf8.GetBytes(allines);


        return data;
    }

Appelez ci-dessous et enregistrez-le en tant que pièce jointe

           Encoding csvEncoding = Encoding.UTF8;
                   //byte[] csvFile = GetCSVFileContent(FileUpload1.PostedFile.FileName);
          byte[] csvFile = GetCSVFileContent("Your_CSV_File_NAme");


        string attachment = String.Format("attachment; filename={0}.csv", "uomEncoded");

        Response.Clear();
        Response.ClearHeaders();
        Response.ClearContent();
        Response.ContentType = "text/csv";
        Response.ContentEncoding = csvEncoding;
        Response.AppendHeader("Content-Disposition", attachment);
        //Response.BinaryWrite(csvEncoding.GetPreamble());
        Response.BinaryWrite(csvFile);
        Response.Flush();
        Response.End();
jAntoni
la source