Я читал похожие сообщения об этом, но они не отвечают на мой вопрос.
В C# у меня есть строка, которую я получаю из WebClient.DownloadString. Я пробовал установить client.Encoding на new UTF8Encoding(false), но это ничего не изменило - я по-прежнему получаю метку порядка байт для UTF-8 в начале строки результата. Мне нужно удалить это (чтобы разобрать полученный XML с помощью LINQ), и я хочу сделать это в памяти.
Итак, у меня есть строка, которая начинается с \x00EF\x00BB\x00BF, и я хочу удалить ее, если она существует. Сейчас я использую
if (xml.StartsWith(ByteOrderMarkUtf8))
{
xml = xml.Remove(0, ByteOrderMarkUtf8.Length);
}
но это кажется неправильным. Я пробовал всевозможные варианты кода с потоками, GetBytes и кодировками, но ничего не работает. Может ли кто-нибудь предоставить "правильный" алгоритм для удаления BOM из строки?
Спасибо!
Недавно у меня были проблемы со .чистая 4 обновления, но до сих пор однозначного ответа
Строку.Отделка()`
удаляет Бом До .net 3.5 с Однако в .сеть 4, вам нужно немного изменить его
String.Trim(new char[]{'\uFEFF'});
Это также позволит избавиться от метки порядка байтов, хотя вы можете также хотеть удалить нулевой ширины пространства от U+200В
String.Trim(new char[]{'\uFEFF','\u200B'});
Это можно также использовать для удаления других нежелательных персонажей
Немного дополнительной информации от http://msdn.microsoft.com/en-us/library/t97s7bs3.aspx
Интернет .Framework 3.5 с пакетом обновления SP1 и более ранних версиях поддерживать внутренний список пробельные символы, что этот метод отделки. Начиная с .Чистая рамки 4, Этот метод удаляет все пробельные символы Юникода (то есть символы, которые производят True возвращаемое значение, если они передаются char.IsWhiteSpace метод). Из-за этого изменения, метод TRIM в .Framework 3.5 с пакетом обновления SP1 и более ранних версиях удаляет два символа, нулевой ширины пространства (U+200B) и нулевой ширины неразрывный пробел (U+FЭФФ), что метод уравновешивания в .Framework 4 и более поздние версии не удаляет. Кроме того, метод уравновешивания в .Framework 3.5 с пакетом обновления SP1 и более ранних версиях не обрезать три пробельные символы Unicode: монгольский гласные разделителя (U+180E), узкий неразрывный пробел (U+202F), и средний математические пробел (U+205F).
У меня были некорректные тестовые данные, что привело меня в замешательство. Основываясь на Как избежать спотыкания о UTF-8 BOM при чтении файлов, я обнаружил, что это работает:
private readonly string _byteOrderMarkUtf8 =
Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
public string GetXmlResponse(Uri resource)
{
string xml;
using (var client = new WebClient())
{
client.Encoding = Encoding.UTF8;
xml = client.DownloadString(resource);
}
if (xml.StartsWith(_byteOrderMarkUtf8, StringComparison.Ordinal))
{
xml = xml.Remove(0, _byteOrderMarkUtf8.Length);
}
return xml;
}
Установка свойства клиента Encoding правильно уменьшает BOM до одного символа. Однако XDocument.Parse по-прежнему не читает эту строку. Это самая чистая версия, которую я придумал на сегодняшний день.
Это работает, как хорошо
int index = xmlResponse.IndexOf('<');
if (index > 0)
{
xmlResponse = xmlResponse.Substring(index, xmlResponse.Length - index);
}
Если переменная xml имеет тип string, то вы уже сделали что-то не так - в символьной строке BOM должен быть представлен не как три отдельных символа, а как одна кодовая точка. Вместо использования DownloadString, используйте DownloadData, а вместо нее разбирайте массивы байтов. Парсер XML должен сам распознать BOM и пропустить его (за исключением автоматического определения кодировки документа как UTF-8).
Быстрый и простой способ, чтобы удалить его directyl из строки:
private static string RemoveBom(string p)
{
string BOMMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
if (p.StartsWith(BOMMarkUtf8))
p = p.Remove(0, BOMMarkUtf8.Length);
return p.Replace("\0", "");
}
Как использовать:
string yourCleanString=RemoveBom(yourBOMString);
У меня была очень похожая проблема (мне нужно для разбора XML-документа представляется в виде байтового массива, который имел метку порядка следования байтов в начале его). Я использовал один из Мартин'ы замечания по его ответу прийти к решению. Я взял массив байтов у меня (вместо преобразования его в строку) и созданный объект потоке MemoryStream
с ним. Затем я передал XDocument используется.Нагрузки, который работал как шарм. Например, пусть'ы сказать, что
xmlBytes` содержит ваш XML в utf8 кодировке с байт-метка в начале его. Тогда это будет код, чтобы решить проблему:
var stream = new MemoryStream(xmlBytes);
var document = XDocument.Load(stream);
Это's, что простой.
Если начинаете со строкой, оно все равно должно быть легко сделать (допустим данных " XML " - это ваша строка, содержащая XML с метки порядка байтов):
var bytes = Encoding.UTF8.GetBytes(xml);
var stream = new MemoryStream(bytes);
var document = XDocument.Load(stream);
Я написал следующее сообщение после прихода на этот вопрос.
По сути, вместо того, чтобы читать в необработанные байты файл'ы содержание с помощью класса BinaryReader, я использую streamreader класс с специальный конструктор, который автоматически удаляет метки порядка байтов персонаж из текстовых данных, я пытаюсь получить.
Передайте байтовый буфер (через DownloadData) в string Encoding.UTF8.GetString(byte[])
, чтобы получить строку, а не загружать буфер КАК строку. Вероятно, у вас больше проблем с вашим текущим методом, чем просто обрезка знака порядка байтов. Если вы не декодируете его правильно, как я предлагаю здесь, символы Юникода, вероятно, будут неправильно интерпретированы, что приведет к повреждению строки.
Редактирование: Ответ Martin'а лучше, поскольку он позволяет избежать выделения целой строки для XML, который все равно нужно разбирать. Ответ, который я дал, лучше всего подходит для общих строк, которые не нужно разбирать как XML.
Я столкнулся с этим, когда я был в base-64 шифрованный файл для преобразования в строку. В то время как я мог бы спасти его в файл и затем прочитать его правильно, здесь's лучшее решение я могу думать, чтобы получить от Байт[]
файл в строку (опираясь слегка на TrueWill'ы ответ):
public static string GetUTF8String(byte[] data)
{
byte[] utf8Preamble = Encoding.UTF8.GetPreamble();
if (data.StartsWith(utf8Preamble))
{
return Encoding.UTF8.GetString(data, utf8Preamble.Length, data.Length - utf8Preamble.Length);
}
else
{
return Encoding.UTF8.GetString(data);
}
}
Где как startswith(байт[])` является логическим продолжением:
public static bool StartsWith(this byte[] thisArray, byte[] otherArray)
{
// Handle invalid/unexpected input
// (nulls, thisArray.Length < otherArray.Length, etc.)
for (int i = 0; i < otherArray.Length; ++i)
{
if (thisArray[i] != otherArray[i])
{
return false;
}
}
return true;
}
Это's, конечно, лучше, если вы можете снять ее, пока еще на уровне байтовый массив, чтобы избежать нежелательных подстрок / allocs. Но если у вас уже есть строка, это, пожалуй, самый простой и наиболее эффективный способ справиться с этим.
Использование:
string feed = ""; // input
bool hadBOM = FixBOMIfNeeded(ref feed);
var xElem = XElement.Parse(feed); // now does not fail
/// <summary>
/// You can get this or test it originally with: Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble())[0];
/// But no need, this way we have a constant. As these three bytes `[239, 187, 191]` (a BOM) evaluate to a single C# char.
/// </summary>
public const char BOMChar = (char)65279;
public static bool FixBOMIfNeeded(ref string str)
{
if (string.IsNullOrEmpty(str))
return false;
bool hasBom = str[0] == BOMChar;
if (hasBom)
str = str.Substring(1);
return hasBom;
}
StreamReader sr = new StreamReader(strFile, true);
XmlDocument xdoc = new XmlDocument();
xdoc.Load(sr);
Еще один универсальный вариант, чтобы избавиться от UTF-8 Бом преамбуле:
var preamble = Encoding.UTF8.GetPreamble();
if (!functionBytes.Take(preamble.Length).SequenceEqual(preamble))
preamble = Array.Empty<Byte>();
return Encoding.UTF8.GetString(functionBytes, preamble.Length, functionBytes.Length - preamble.Length);
Я решил проблему с помощью следующего кода
using System.Xml.Linq;
void method()
{
byte[] bytes = GetXmlBytes();
XDocument doc;
using (var stream = new MemoryStream(docBytes))
{
doc = XDocument.Load(stream);
}
}