Как я могу преобразовать строку в UTF-8 в C #?

146

У меня есть строка, которую я получаю из стороннего приложения, и я хотел бы правильно отобразить ее на любом языке, используя C #, на моей Windows Surface.

Из-за неправильной кодировки часть моей строки на испанском выглядит так:

Acción

тогда как это должно выглядеть так:

Acción

Согласно ответу на этот вопрос: Как узнать кодировку строк в C # , кодировка, которую я получаю, должна уже поступать в UTF-8, но она читается в Encoding.Default (возможно, ANSI?).

Я пытаюсь преобразовать эту строку в настоящий UTF-8, но одна из проблем заключается в том, что я могу видеть только подмножество класса Encoding (только свойства UTF8 и Unicode), вероятно, потому, что я ограничен интерфейсом Windows Surface.

Я попробовал некоторые фрагменты, которые я нашел в Интернете, но ни один из них не оказался успешным для восточных языков (например, корейский). Один пример выглядит следующим образом:

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.
SLaks
Вот пример строки , которая не работает на английском языке: вместо отображения дня, мой передний конец приложение отображает: Дайя € ™ s
Гаара

Ответы:

251

Как вы знаете, строка поступает так, как Encoding.Defaultвы могли бы просто использовать:

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

Еще одна вещь, которую вы, возможно, должны помнить: если вы используете Console.WriteLine для вывода некоторых строк, то вы также должны написать Console.OutputEncoding = System.Text.Encoding.UTF8;!!! Или все строки utf8 будут представлены как gbk ...

anothershrubery
источник
Это тоже работает, на самом деле это намного лучше, чем мой ответ, который также работает. Я даю вам +1
отличную
Спасибо! Проблема в том, что, как я упоминал в описании, API для поверхности неполон (для меня нет Encoding.Default).
Гаара
3
@ Гаара: попробуй Encoding.GetEncoding(...); вам нужно будет найти имя фактической кодировки, которая была неправильно использована на другом конце.
SLaks
1
Вы можете объяснить, почему это работает? если значение по умолчанию - GB2312, то Encoding.Default.GetBytes будет кодировать строку в байтовый массив с использованием кодера GB2312, а затем Encoding.UTF8.GetString попытается декодировать байтовый массив с использованием декодера UTF8, результат должен быть неправильным, но почему это работает. @anothershrubery
guorongfei
1
@guorongfei Суть в том, что myStringэто моджибаке. Код сначала отменяет неправильное декодирование, затем выполняет правильное декодирование. Это работает, пока неправильное декодирование не потеряло данные. Но, как указал @SLaks, было бы лучше использовать точную кодировку, которая была неправильной. (Более точные имена и комментарии в коде помогут понять, насколько неправильно выглядящий код на самом деле является попыткой сделать правильно.)
Том Блоджет,
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);

Вывод должен выглядеть так

Acción

дневные показы дневные

вызвать DecodeFromUtf8 ();

private static void DecodeFromUtf8()
{
    string utf8_String = "day’s";
    byte[] bytes = Encoding.Default.GetBytes(utf8_String);
    utf8_String = Encoding.UTF8.GetString(bytes);
}
Methodman
источник
1
Спасибо! Это работает на испанском языке, проблема в том, что то же самое не будет работать на восточных языках (то есть на корейском). Я пытаюсь найти 8-битный алгоритм преобразования UTF-8 в интернете, но все равно не повезло.
Гаара
Вот пример строки , которая не работает на английском языке: вместо отображения дня, мой передний конец приложение отображает: Дайя € ™ s
Гаара
Хорошо, позвольте мне возиться с этим и посмотреть, что я могу придумать
MethodMan
Я проверил, и он возвращает день. Я вставлю статический метод, который я тестировал, он на самом деле такой же, как в @anothershrubery
MethodMan
Вы можете изменить этот метод, передав DecodeFromUtf8 (строка utf8string);
MethodMan
12

Ваш код читает последовательность байтов в кодировке UTF8 и декодирует их с использованием 8-битной кодировки.

Вам нужно исправить этот код, чтобы декодировать байты как UTF8.

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

SLaks
источник
Спасибо! Проблема в том, что сторонним приложением является C ++, а мой код - C #, поэтому я полагаю, что декодирование происходит в «мосте» между этими двумя.
Гаара
8
 Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(mystring));
Риад Хаммуда
источник
5

Если вы хотите сохранить любую строку в базе данных MySQL, сделайте это: ->

Структура поля вашей базы данных в phpmyadmin [или любой другой панели управления] должна быть установлена ​​в utf8-gerneral-ci

2) вы должны изменить свою строку [Пример. textbox1.text] для байта, поэтому

2-1) определить byte [] 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();
jAntoni
источник