Як я можу перетворити рядок на UTF-8 у C #?


146

У мене є рядок, який я отримую від стороннього додатка, і я хотів би правильно відобразити його будь-якою мовою за допомогою C # на моїй поверхні Windows.

Через неправильне кодування фрагмент моєї рядка виглядає так на іспанській мові:

Acción

тоді як це має виглядати так:

Acción

Відповідно до відповіді на це запитання: Як знати кодування рядків у C # , кодування, яке я отримую, повинно надходити вже на UTF-8, але воно читається на Encoding.Default (можливо, ANSI?).

Я намагаюся перетворити цю рядок у реальний UTF-8, але одна з проблем полягає в тому, що я бачу лише підмножину класу Encoding (лише властивості UTF8 та Unicode), ймовірно, тому, що я обмежений API поверхні Windows.

Я спробував кілька фрагментів, які знайшов в Інтернеті, але жоден з них поки що не виявився успішним для східних мов (тобто корейської). Один з таких прикладів:

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

Я також спробував витягти рядок у байтовий масив, а потім за допомогою 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);

У вас, хлопці, є якісь інші ідеї, які я міг би спробувати?


5
Ваша проблема пов’язана з кодом, який створив в першу чергу рядок (з потоку чи байта []). Покажіть цей код.
SLaks

1
@Oded: .Net рядки зберігаються в пам'яті як UTF16, але Encoding.Defaultповертає кодову сторінку ANSI системи.
СЛАкс

Ось приклад рядка, який не працює на англійській мові: замість того, щоб відображати день, відображається мій передній додаток: dayâ € ™ s
Gaara

Відповіді:


251

Як ви знаєте, рядок надходить так, як Encoding.Defaultви можете просто використовувати:

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

Ще одна річ, яку ви, можливо, повинні запам’ятати: Якщо ви використовуєте Console.WriteLine для виведення деяких рядків, то вам також слід написати Console.OutputEncoding = System.Text.Encoding.UTF8;!!! Або всі рядки utf8 будуть виписані як gbk ...


Це теж працює, це насправді набагато приємніше, ніж моя відповідь, яка також працює, я даю вам 1 хорошу роботу
MethodMan

Дякую! Проблема полягає в тому, що, як я вже згадував в описі, API для поверхні є неповним (для мене немає Encoding.Default).
Гаара

3
@Gaara: Спробуйте Encoding.GetEncoding(...); вам потрібно буде знайти ім’я фактичного кодування, яке було неправильно використано на іншому кінці.
СЛАкс

1
Ви можете пояснити, чому це працює? якщо за замовчуванням є GB2312, то Encoding.Default.GetBytes буде кодувати рядок для байтового масиву використовувати кодер GB2312, потім Encoding.UTF8.GetString спробує розшифрувати байтовий масив з використанням декодера UTF8, результат повинен бути неправильним, але чому це працює. @anothershrubery
guorongfei

1
@guorongfei Передумовою є те, що myStringє mojibake. Код спочатку скасовує неправильне декодування, потім робить правильне декодування. Він працює до тих пір, поки неправильне декодування не втратило дані. Але як зазначав @SLaks, було б краще використовувати точне кодування, яке було неправильним. (Кращі назви та коментарі в коді допоможуть зрозуміти, як дуже неправильний вигляд коду насправді є спробою зробити правильно.)
Том Блоджет

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

Вихід повинен виглядати так

Acción

dayâ € ™ s відображає день

виклик DecodeFromUtf8 ();

private static void DecodeFromUtf8()
{
    string utf8_String = "day’s";
    byte[] bytes = Encoding.Default.GetBytes(utf8_String);
    utf8_String = Encoding.UTF8.GetString(bytes);
}

1
Дякую! Це працює по-іспанськи, проблема полягає в тому, що те саме не буде працювати на східних мовах (тобто корейській). Я намагаюся шукати 8-бітний алгоритм перетворення UTF-8 в Інтернеті, але все одно не пощастило.
Гаара

Ось приклад рядка, який не працює на англійській мові: замість того, щоб відображати день, відображається мій передній додаток: dayâ € ™ s
Gaara

добре, дозвольте мені зіткнутися з цим і подивитися, що я можу придумати
MethodMan

Я тестував, і він повертає день, я вставлю статичний метод, який я перевірив, він насправді такий самий, що і @anothershrubery надав
MethodMan

ви можете змінити цей метод, передавши DecodeFromUtf8 (рядок utf8string);
Метод

12

Ваш код читає послідовність байтів, кодованих UTF8, і розшифровує їх за допомогою 8-бітного кодування.

Вам потрібно виправити цей код, щоб декодувати байти як UTF8.

Альтернативно ( не ідеально ), ви можете перетворити поганий рядок назад у вихідний масив байтів - кодуючи його за допомогою неправильного кодування - і потім повторно розшифрувати байти як UTF8.


Дякую! Проблема полягає в тому, що стороннє додаток - це C ++, а мій код - це C #, тому я гадаю, що декодування відбувається в "мості" між цими двома.
Гаара


5

Якщо ви хочете зберегти будь-який рядок до бази даних mysql, зробіть це: ->

Структуру поля вашої бази даних i phpmyadmin [або будь-яку іншу панель керування] слід встановити на utf8-gerneral-ci

2) слід змінити рядок [Перш. textbox1.text] в байт, для цього

2-1) визначити байт [] st2;

2-2) перетворити рядок [textbox1.text] в unicode [mmultibyte string] шляхом:

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

3) виконати цю команду sql перед будь-яким запитом:

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

3-2) тепер слід вставити це значення у поле для прикладу, наприклад:

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

4) Основна робота, на яку багато хто не звернув на це уваги, - це наступний рядок: слід використовувати addwithvalue замість параметра add в командному параметрі, як показано нижче:

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

+++++++++++++++++++++++++++++++++++ насолоджуйтесь реальними даними на сервері бази даних замість ????


3

Використовуйте наведений нижче фрагмент коду, щоб отримати байти з файлу 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;
    }

Зателефонуйте нижче та збережіть його як вкладення

           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();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.