В .net я хочу декодировать некоторые необработанные данные, закодированные приложением C ++. Приложение C ++ является 32-разрядным, а приложение C # — 64-разрядным.
Приложение C ++ поддерживает русские и испанские символы, но он не поддерживает символы Юникода. Этот двоичный читатель C # не может читать русские или испанские символы и работает только для английских символов ascii.
CArchive не указывает никакой кодировки, и я не уверен, как читать его из C #.
Я проверил это на пару простых строк, это то, что обеспечивает C ++ CArchive:
Для «Азбуки»: «03 41 42 43»
Для «ÁåëÀÇ 7555»: «0B C1 E5 EB C0 C7 20 37 35 35 35 C2»
Ниже показано, как приложение C ++ записывает двоичный файл.
void CColumnDefArray::SerializeData(CArchive& Archive)
{
int iIndex;
int iSize;
int iTemp;
CString sTemp;
if (Archive.IsStoring())
{
Archive << m_iBaseDataCol;
Archive << m_iNPValueCol;
iSize = GetSize();
Archive << iSize;
for (iIndex = 0; iIndex < iSize; iIndex++)
{
CColumnDef& ColumnDef = ElementAt(iIndex);
Archive << (int)ColumnDef.GetColumnType();
Archive << ColumnDef.GetColumnId();
sTemp = ColumnDef.GetName();
Archive << sTemp;
}
}
}
И вот как я пытаюсь прочитать это в C #.
Далее можно расшифровать «Азбуку», но не русские символы. Я проверял this.Encoding
со всеми доступными опциями (Ascii, UTF7 и т. д.). Русские символы работают только для Encoding.Default. Но, очевидно, это ненадежный вариант, так как кодирование и декодирование обычно происходит на разных компьютерах.
public override string ReadString()
{
byte blen = ReadByte();
if (blen < 0xff)
{
// *** For russian characters it comes here.***
return this.Encoding.GetString(ReadBytes(blen));
}
var slen = (ushort) ReadInt16();
if (slen == 0xfffe)
{
throw new NotSupportedException(ServerMessages.UnicodeStringsAreNotSupported());
}
if (slen < 0xffff)
{
return this.Encoding.GetString(ReadBytes(slen));
}
var ulen = (uint) ReadInt32();
if (ulen < 0xffffffff)
{
var bytes = new byte[ulen];
for (uint i = 0; i < ulen; i++)
{
bytes[i] = ReadByte();
}
return this.Encoding.GetString(bytes);
}
//// Not support for 8-byte lengths
throw new NotSupportedException(ServerMessages.EightByteLengthStringsAreNotSupported());
}
Какой правильный подход для декодирования этого? Как вы думаете, выбор правильной кодовой страницы — способ решить эту проблему? Если да, то как узнать, какая кодовая страница использовалась для кодирования?
Цените, если кто-то может показать мне правильное направление, чтобы сделать это.
редактировать
Похоже этот вопрос а также «Абсолютный минимум, который должен знать каждый разработчик программного обеспечения, абсолютно точно должен знать о Unicode и наборах символов (никаких оправданий!)» Статья разрешит некоторые сомнения. По-видимому, нет способа найти правильную кодовую страницу для существующих данных.
Я думаю, теперь вопрос: есть ли кодовая страница, которая поддерживает все испанские, русские и английские символы? Могу ли я указать кодовую страницу в классе C ++ CArchive?
Программа не на Unicode C ++ записывает данные как 0B C1 E5 EB C0 C7 20 37 35 35 35 C2
(длина строки, затем bytes
)
"ÁåëÀÇ 7555Â"
это представление bytes
в кодовой странице 1252
На английском языке компьютер возвращает следующий код "ÁåëÀÇ 7555Â"
, Это работает, если обе программы используют одну и ту же кодовую страницу:
string result = Encoding.Default.GetString(bytes);
Вы также можете использовать кодовую страницу 1252 напрямую. Это гарантирует, что результат всегда "ÁåëÀÇ 7555Â"
для этого конкретного набора байтов:
//result will be `"ÁåëÀÇ 7555Â"`, always
Encoding cp1252 = Encoding.GetEncoding(1252);
string result = cp1252.GetString(bytes);
Однако это не может решить никаких проблем. Рассмотрим пример с греческим текстом:
string greek = "ελληνικά";
Encoding cp1253 = Encoding.GetEncoding(1253);
var bytes = cp1253.GetBytes(greek);
bytes
будет аналогичен выводу программы C ++. Вы можете использовать ту же технику для извлечения текста:
//result will be "åëëçíéêÜ"Encoding cp1252 = Encoding.GetEncoding(1252);
string result = cp1252.GetString(bytes);
Результат "åëëçíéêÜ"
, Но желаемый результат "ελληνικά"
//result will be "ελληνικά"Encoding cp1253 = Encoding.GetEncoding(1253);
string greek_decoded = cp1253.GetString(bytes);
Таким образом, чтобы сделать правильное преобразование, вы должны иметь исходную кодовую страницу, которую использовала программа C ++ (Я просто повторяю Ганса Пассанта)
Вы можете сделать следующую модификацию:
public override string ReadString()
{
//Default code page if both programs use the same code page
Encoding encoder = System.Text.Encoding.Default;
//or find out what code page the C++ program is using
//Encoding encoder = System.Text.Encoding.GetEncoding(codepage);
//or use English code page to always get "ÁåëÀÇ 7555Â"...
//Encoding encoder = System.Text.Encoding.GetEncoding(1252);
//(not recommended)
byte blen = ReadByte();
if (blen < 0xff)
return encoder.GetString(ReadBytes(blen));
var slen = (ushort)ReadInt16();
if (slen == 0xfffe)
throw new NotSupportedException(
ServerMessages.UnicodeStringsAreNotSupported());
if (slen < 0xffff)
return encoder.GetString(ReadBytes(blen));
var ulen = (uint)ReadInt32();
if (ulen < 0xffffffff)
{
var bytes = new byte[ulen];
for (uint i = 0; i < ulen; i++)
bytes[i] = ReadByte();
return encoder.GetString(ReadBytes(blen));
}
throw new NotSupportedException(
ServerMessages.EightByteLengthStringsAreNotSupported());
}
Дополнительные комментарии:
Программа не-Unicode MFC может принимать ввод на английском или русском языке, но не на обоих языках одновременно. Эти старые программы используют char
хранить до 255 букв на байт. 255 не хватает места для всех алфавитов на английском, русском, греческом, арабском …
Кодовая страница 1252 сопоставляет символы латинским алфавитам. В то время как кодовая страница 1253 отображает символы на греческий алфавит и так далее.
Поэтому ваш файл MFC содержит только один язык одной кодовой страницы.
Западноевропейские языки (английский, испанский, португальский, немецкий, французский, итальянский, шведский и т. Д.) Используют кодовую страницу 1252. Если пользователи остаются в этой языковой группе, проблем не должно быть. System.Text.Encoding.Default
должен решить проблему, или еще лучше System.Text.Encoding.GetEncoding(variable_codepage)
В Windows есть несколько соответствующих кодовых страниц ANSI
874 – Windows Thai 1250 – Windows Central and East European Latin 2 1251 – Windows Cyrillic 1252 – Windows West European Latin 1 1253 – Windows Greek 1254 – Windows Turkish 1255 – Windows Hebrew 1256 – Windows Arabic 1257 – Windows Baltic 1258 – Windows Vietnamese
Некоторые азиатские языки не поддерживаются без Unicode. Некоторые символы Unicode не поддерживаются в ANSI, с этим ничего не поделаешь.
Можно заставить программу, не поддерживающую Юникод, использовать более одной кодовой страницы. Но это не практично. Гораздо проще перейти на Unicode и сделать это правильно.
Смотрите также Минимальные разработчики программного обеспечения должны знать о Unicode
Других решений пока нет …