Как игнорировать маркер порядка байтов UTF-8 в сравнениях строк? - PullRequest
15 голосов
/ 26 мая 2010

У меня проблема со сравнением строк в модульном тесте в C # 4.0 с использованием Visual Studio 2010. Этот же тестовый пример работает правильно в Visual Studio 2008 (с C # 3.5).

Вот соответствующий фрагмент кода:

byte[] rawData = GetData();
string data = Encoding.UTF8.GetString(rawData);

Assert.AreEqual("Constant", data, false, CultureInfo.InvariantCulture);

При отладке этого теста строка data кажется невооруженным глазом содержащей точно такую ​​же строку, что и литерал. Когда я позвонил data.ToCharArray(), я заметил, что первый байт строки data - это значение 65279, которое представляет собой маркер порядка байтов UTF-8. Я не понимаю, почему Encoding.UTF8.GetString() хранит этот байт.

Как мне заставить Encoding.UTF8.GetString() до не поместить маркер порядка байтов в результирующую строку?

Обновление: Проблема заключалась в том, что GetData(), который читает файл с диска, считывает данные из файла, используя FileStream.readbytes(). Я исправил это, используя StreamReader и преобразовав строку в байты, используя Encoding.UTF8.GetBytes(), что и должно было быть в первую очередь! Спасибо за помощь.

Ответы [ 3 ]

16 голосов
/ 26 мая 2010

Ну, я предполагаю, что это потому, что необработанные двоичные данные включают в себя спецификацию.Вы всегда можете удалить спецификацию самостоятельно после декодирования, если вам это не нужно, но вам следует подумать, должен ли байтовый массив учитывать спецификацию, с которой начинается.* выполнить декодирование.Вот пример, показывающий тот же байтовый массив, который преобразуется в два символа с использованием Encoding.GetString или один символ с помощью StreamReader:

using System;
using System.IO;
using System.Text;

class Test
{
    static void Main()
    {
        byte[] withBom = { 0xef, 0xbb, 0xbf, 0x41 };
        string viaEncoding = Encoding.UTF8.GetString(withBom);
        Console.WriteLine(viaEncoding.Length);

        string viaStreamReader;
        using (StreamReader reader = new StreamReader
               (new MemoryStream(withBom), Encoding.UTF8))
        {
            viaStreamReader = reader.ReadToEnd();           
        }
        Console.WriteLine(viaStreamReader.Length);
    }
}
8 голосов
/ 27 мая 2010

Существует несколько более эффективный способ сделать это, чем создание StreamReader и MemoryStream:

1) Если вы знаете, что всегда есть спецификация

string viaEncoding = Encoding.UTF8.GetString(withBom, 3, withBom.Length - 3);

2) Если вы не знаете, отметьте:

string viaEncoding;
if (withBom.Length >= 3 && withBom[0] == 0xEF && withBom[1] == 0xBB && withBom[2] == 0xBF)
    viaEncoding = Encoding.UTF8.GetString(withBom, 3, withBom.Length - 3);
else
    viaEncoding = Encoding.UTF8.GetString(withBom);
0 голосов
/ 26 мая 2010

Я считаю, что дополнительный символ удаляется, если вы обрезаете () декодированную строку

...