Как игнорировать маркер порядка байтов UTF-8 в сравнении строк?

У меня возникла проблема сравнения строк в Unit Test в С# 4.0 с использованием Visual Studio 2010. Этот же пример теста работает правильно в Visual Studio 2008 (с С# 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(), что и должно было делать в первую очередь! Спасибо за помощь.

Ответы

Ответ 1

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

EDIT: В качестве альтернативы вы можете использовать StreamReader для выполнения декодирования. Здесь пример, показывающий тот же массив байтов, который преобразуется в два символа с использованием 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);
    }
}

Ответ 2

Существует несколько более эффективный способ сделать это, чем создавать 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);

Ответ 3

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