Преобразование C# UNICODE в ANSI

Мне нужна ваша помощь по поводу того, что меня беспокоит при работе с кодировкой UNICODE в .NET Framework...

Мне приходится взаимодействовать с некоторыми системами данных клиентов с приложениями, отличными от UNICODE, и у этих клиентов есть компании по всему миру (китайские, корейские, российские, ...). Поэтому они должны предоставить мне 8-битный файл ASCII, который будет закодирован их кодовой страницей Windows.

Таким образом, если клиент из Греции пришлет мне текстовый файл, содержащий 'Σ' (сигма-буква 'Σ') в названии продукта, я получу эквивалентную букву, соответствующую кодовой точке 211 ANSI, представленной на моей собственной кодовой странице. На моем компьютере установлена ​​французская Windows, что означает, что кодовая страница Windows-1252, поэтому в этом текстовом файле я буду использовать вместо 'Ó'... Хорошо.

Я знаю, что этот клиент грек, поэтому я могу прочитать его файл, задав кодовую страницу windows-1253 в параметрах импорта.

/// <summary>
/// Convert a string ASCII value using code page encoding to Unicode encoding
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToUnicode(string value, int codePage)
{
    Encoding windows = Encoding.Default;
    Encoding unicode = Encoding.Unicode;
    Encoding sp = Encoding.GetEncoding(codePage);
    if (sp != null && !String.IsNullOrEmpty(value))
    {
        // First get bytes in windows encoding
        byte[] wbytes = windows.GetBytes(value);

        // Check if CodePage to use is different from current Windows one
        if (windows.CodePage != sp.CodePage)
        {
            // Convert to Unicode using SP code page
            byte[] ubytes = Encoding.Convert(sp, unicode, wbytes);
            return unicode.GetString(ubytes);
        }
        else
        {
            // Directly convert to Unicode using windows code page
            byte[] ubytes = Encoding.Convert(windows, unicode, wbytes);
            return unicode.GetString(ubytes);
        }
    }
    else
    {
        return value;
    }
}

Ну, в конце концов, я получил «Σ» в своем приложении, и я могу сохранить его в своей базе данных SQL Server. Теперь мое приложение должно выполнить некоторые сложные вычисления, а затем я должен вернуть этот файл клиенту с автоматическим экспортом...

Итак, моя проблема в том, что я должен выполнить преобразование UNICODE => ANSI?! Но это не так просто, как я думал вначале...

Я не хочу сохранять кодовую страницу, используемую во время импорта, поэтому моей первой идеей было преобразовать UNICODE в windows-1252, а затем автоматически отправить файл клиентам. Они будут читать экспортированный текстовый файл со своей кодовой страницей, поэтому эта идея меня заинтересовала.

Но проблема в том, что преобразование таким образом ведет себя странно... Вот два разных примера:

1-й пример (я)

char ya = '\u042F';
string strYa = Char.ConvertFromUtf32(ya);
System.Text.Encoding unicode = System.Text.Encoding.Unicode;
System.Text.Encoding ansi1252 = System.Text.Encoding.GetEncoding(1252);
System.Text.Encoding ansi1251 = System.Text.Encoding.GetEncoding(1251);

string strYa1252 = ansi1252.GetString(System.Text.Encoding.Convert(unicode, ansi1252, unicode.GetBytes(strYa)));
string strYa1251 = ansi1251.GetString(System.Text.Encoding.Convert(unicode, ansi1251, unicode.GetBytes(strYa)));

Таким образом, strYa1252 содержит '?', тогда как strYa1251 содержит действительный char 'я'. Таким образом, кажется, что невозможно преобразовать в ANSI, если действительная кодовая страница не указана для функции Convert () ... Итак, ничто в классе кодирования Unicode не помогает пользователю получить эквивалентность между кодовыми точками ANSI и UNICODE? :\

2-й пример (Σ)

char sigma = '\u3A3';
string strSigma = Char.ConvertFromUtf32(sigma);
System.Text.Encoding unicode = System.Text.Encoding.Unicode;
System.Text.Encoding ansi1252 = System.Text.Encoding.GetEncoding(1252);
System.Text.Encoding ansi1253 = System.Text.Encoding.GetEncoding(1253);

string strSigma1252 = ansi1252.GetString(System.Text.Encoding.Convert(unicode, ansi1252, unicode.GetBytes(strSigma)));
string strSigma1253 = ansi1253.GetString(System.Text.Encoding.Convert(unicode, ansi1253, unicode.GetBytes(strSigma)));

В настоящее время у меня есть правильный «Σ» в строке strSigma1253, но у меня также есть «S» для strSigma1252< /сильный>. Как указано в начале, у меня должен быть 'Ó', если был найден код ANSI, или '?' если символ не найден, но не 'S'. Почему? Да, конечно, лингвист мог бы сказать, что буква «S» эквивалентна греческой букве сигма, потому что они звучат одинаково в обоих алфавитах, но у них разные коды ANSI!

Итак, как функция Convert() в среде .NET может справиться с такой эквивалентностью?

И есть ли у кого-нибудь идея записывать символы ANSI из UNICODE в текстовые файлы, которые я должен отправлять клиентам?


person alex    schedule 10.06.2013    source источник
comment
Вам действительно нужно знать кодовую страницу клиента, прежде чем вы сможете преобразовать текст обратно в кодовую страницу клиента. Если у вас нет этой информации, вы не сможете это сделать.   -  person Matthew Watson    schedule 10.06.2013
comment
Например, если вы посмотрите на MSDN кодовую страницу Windows-1252 (msdn.microsoft. com/en-us/goglobal/cc305145.aspx), внизу этой страницы есть список взаимосвязей между кодами ANSI 1252 и кодовыми точками UNICODE... Так что я подумал, что при переходе существует эквивалентность из UNICODE в одну или несколько кодовых страниц ANSI? Пример: fileformat.info/info/unicode/char/3a3/charset_support. htm, где есть все коды, соответствующие сигме для всех кодовых страниц Windows...   -  person alex    schedule 10.06.2013
comment
Возможно, будет лучше, если ваши клиенты сами будут работать в UTF-8 или Unicode. Вы также контролируете программное обеспечение, которое они используют?   -  person Rup    schedule 10.06.2013
comment
Вовсе нет, в этом проблема: P Мы предоставляем интерфейсы только для нашего и их приложений, которые часто представляют собой некоторые старые самодельные (и не-UNICODE) промышленные программы .... Думаю, я бы не опубликовал этот вопрос, если решение заключалась в том, чтобы перевести клиентов на некоторые промышленные приложения UTF8 ^^ Мне действительно нужно обеспечить совместимость с их системой, вернув 8-битный файл ASCII ...   -  person alex    schedule 10.06.2013
comment
Нет такой вещи, как 8-битный ASCII. Таким образом, вы ДОЛЖНЫ знать, какую кодовую страницу сохранять.   -  person dda    schedule 10.06.2013
comment
Хммм ... Это очень хорошая новость для меня, если вы правы :\ Я действительно думал, что существуют эквивалентности [0-n] из UNICODE всем различным кодовым страницам ANSI ... А как насчет Sigma, которая преобразуется в ' S 'в кодовой странице Windows-1252? Есть ли у кого-нибудь идея относительно этого неявного преобразования?   -  person alex    schedule 10.06.2013
comment
Вы обязательно должны спросить всех своих клиентов, какие кодовые страницы они используют, чтобы составить список, который вам понадобится, а также спросить, захотят ли они использовать вместо этого UTF-8, если вы думаете, что вам это сойдет с рук. Они могут только сказать нет!   -  person Rup    schedule 10.06.2013


Ответы (1)


Мне следует иметь ...'?' если символ не найден, но не 'S'. Почему?

Это известно как «наилучшее» кодирование, и в большинстве случаев это плохо. Когда Windows не может закодировать символ в целевую кодовую страницу (поскольку Σ не существует в кодовой странице 1252), она делает все возможное, чтобы сопоставить символ с чем-то похожим на него. Это может означать потерю диакритических знаков (ëe) или сопоставление с родственным символом (ΣS), родственным символом (=), несвязанным символом, но немного похожим (8) или любая другая замена сумасброда казалась хорошей идеей в то время, но на практике оказывалась оскорбительной с культурной или математической точки зрения.

Вы можете увидеть таблицы для cp1252, включая это сопоставление Sigma, здесь .

Помимо того, что это бесшумное искажение сомнительной полезности, у него также есть некоторые довольно плохие последствия для безопасности. Вы должны иметь возможность остановить это, установив EncoderFallback до ReplacementFallback или ExceptionFallback.

есть ли у кого-нибудь идея вернуть символы ANSI из UNICODE в текстовые файлы, которые я должен отправить клиентам?

Вам придется вести таблицу кодировок для каждого клиента. Прочитайте их входные файлы, используя эту кодировку для декодирования; записывать свои выходные файлы, используя ту же кодировку.

(Для здравого смысла установите для новых клиентов UTF-8 и задокументируйте, что это предпочтительная кодировка.)

person bobince    schedule 10.06.2013