Как правильно сравнить строку и байты? - PullRequest
1 голос
/ 28 сентября 2019

Я пытаюсь прочитать какой-то файл в байтах и ​​сравнить его с "\ u0019 \ u0093 \ r \ n \ u001a \ n".И я уверен, что всегда буду получать byte [] {0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a}.

Я пытался преобразовать эти байты в строку и сравнивать со строкой, но всегда ложно.

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

(Использование .NET Core 3.0 в Windows 10)

Я пробовал как следующий код

byte[] bytes = new byte[]{ 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a };
string s = "\u0019\u0093\r\n\u001a\n";
System.Console.WriteLine(Encoding.Default.GetString(bytes) == s);
System.Console.WriteLine(s.Length);
foreach (var b in Encoding.Default.GetBytes(s))
{
    System.Console.WriteLine("Byte: "+b);
}
System.Console.WriteLine(Encoding.Default.GetString(bytes) == s);

, вывод:

False
6
Byte: 25
Byte: 194
Byte: 147
Byte: 13
Byte: 10
Byte: 26
Byte: 10
False

Сравнение всегда возвращает false.Я обнаружил, что после преобразования строки в байты я получил еще один дополнительный байт и понятия не имею, откуда взялись эти 194.Почему это происходит?

Я полагаю, они должны быть равны после преобразования.Это неправильно?

Что мне делать, если я хочу получить то, что ожидаю?

1 Ответ

1 голос
/ 29 сентября 2019

Код символа в исходных закодированных байтах: 0x0093.

Проблема, с которой вы сталкиваетесь, заключается в кодировке Default в вашей системе (которая в Windows собираетсякакой бы ни была текущая кодовая страница системы), символ, закодированный как 0x0093, не распознается.Поэтому, когда вы пытаетесь его декодировать, вы получаете символьную точку UTF16 0xfffd (которая используется по умолчанию для декодеров .NET для нераспознанных символов).Затем это кодируется обратно в кодировку по умолчанию как 0x93c2 (последовательность байтов, которые вы видите в выходных данных, в десятичном формате, который 194 сопровождается 147).

Для чего это стоитповедение соответствует кодировке по умолчанию, установленной на UTF8, что может указывать на то, что это система Linux (в большинстве систем Windows в качестве кодировки по умолчанию используется некоторая кодовая страница, специфичная для локали, а не UTF8).

Если вы хотите дляИсходный байт 0x93 для перевода в символ UTF16, имеющий по существу то же значение (т. е. 0x0093, он же '\u0093'), затем вам необходимо декодировать исходные байты, используя текстовую кодировку, где кодовая точка 0x93 фактически выполняетперевести на кодовую точку UTF16 0x0093.

К счастью, есть веб-сайт, который на самом деле скажет нам, для каких кодировок есть этот символ и каково их значение: https://www.compart.com/en/unicode/charsets/containing/U+0093

И из этой таблицы мы можем видеть большое количество кодировок, где это имеет место (есть также некоторые кодировки, в которых символ UTF16 '\u0093' кодируется как другое значение, а именно 0x33… очевидно, мы не хотим ничего из этого).Первая кодировка в списке - «ISO-8859-1» - кажется подходящей, поэтому давайте попробуем использовать ее для декодирования ваших байтов:

byte[] bytes = new byte[] { 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a };
string s = "\u0019\u0093\r\n\u001a\n";
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
System.Console.WriteLine(encoding.GetString(bytes) == s);
System.Console.WriteLine(s.Length);
foreach (var b in encoding.GetBytes(s))
{
    System.Console.WriteLine("Byte: " + b);
}
System.Console.WriteLine(encoding.GetString(bytes) == s);

Это выводит именно то, что вы хотите:

True
6
Byte: 25
Byte: 147
Byte: 13
Byte: 10
Byte: 26
Byte: 10
True

И отображаемые байты являются даже точными байтами в вашем массиве bytes, что мы можем продемонстрировать, добавив эту строку в конец вашей программы:

System.Console.WriteLine(encoding.GetBytes(s).SequenceEqual(bytes));

Это также выведет True.

И мораль этой истории такова: знание оригинальной кодировки байтов, которые вы пытаетесь декодировать , необязательно .Вы должны точно знать, какая кодировка использовалась, потому что это просто: кодировка .Вы также можете пытаться декодировать зашифрованные данные, если используете неправильную кодировку.

Различные кодировки текста по определению различны.Это означает, что байты в одной кодировке означают нечто совершенно иное, чем в какой-либо другой кодировке (вроде ... большинство кодировок перекрываются в самых низких 128 кодовых точках, поскольку все они основаны на ASCII).Вы просто получите случайные результаты, если будете использовать неправильную кодировку для декодирования некоторых байтов (или, как в этом случае, декодер просто не распознает символ и преобразует его в заполнитель, представляющий нераспознанный символ).

...