Faixa Byte Order Mark da string em C #

Eu li posts semelhantes sobre isso e eles não respondem a minha pergunta.

Em C #, eu tenho uma string que estou obtendo de WebClient.DownloadString. Eu tentei definir client.Encoding para novo UTF8Encoding (false), mas isso não fez diferença – eu ainda acabo com uma marca de ordem de byte para UTF-8 no início da seqüência de resultado. Eu preciso remover isso (para analisar o XML resultante com o LINQ) e quero fazer isso na memory.

Então eu tenho uma string que começa com \ x00EF \ x00BB \ x00BF, e eu quero remover isso, se existir. Agora estou usando

if (xml.StartsWith(ByteOrderMarkUtf8)) { xml = xml.Remove(0, ByteOrderMarkUtf8.Length); } 

mas isso parece errado. Eu tentei todos os tipos de código com streams, GetBytes e codificações e nada funciona. Alguém pode fornecer o algoritmo “certo” para retirar uma lista de materiais de uma string?

Obrigado!

Se a variável xml for do tipo string, você já fez algo errado – em uma sequência de caracteres, a BOM não deve ser representada como três caracteres separados, mas como um único ponto de código. Em vez de usar o DownloadString, use DownloadData e analise os arrays de bytes. O analisador XML deve reconhecer o próprio BOM e ignorá-lo (exceto para detectar automaticamente a codificação do documento como UTF-8).

Recentemente, tive problemas com a atualização .net 4, mas até então a resposta simples é

String.Trim()

remove a BOM até .net 3.5 No entanto, em .net 4 você precisa alterá-lo ligeiramente

 String.Trim(new char[]{'\uFEFF'}); 

Isso também elimina a marca do Byte order, embora você também queira remover o ZERO WIDTH SPACE U + 200B

 String.Trim(new char[]{'\uFEFF','\u200B'}); 

Isso você também pode usar para remover outros caracteres indesejados

Mais informações em http://msdn.microsoft.com/pt-br/library/t97s7bs3.aspx

O .NET Framework 3.5 SP1 e versões anteriores mantêm uma lista interna de caracteres de espaço em branco que esse método apara. Começando com o .NET Framework 4, o método apara todos os caracteres de espaço em branco Unicode (ou seja, caracteres que produzem um valor de retorno verdadeiro quando são passados ​​para o método Char.IsWhiteSpace). Devido a essa alteração, o método Trim no .NET Framework 3.5 SP1 e em versões anteriores remove dois caracteres, ZERO WIDTH SPACE (U + 200B) e ZERO WIDTH NO-BREAK SPACE (U + FEFF), que o método Trim no. NET Framework 4 e versões posteriores não remove. Além disso, o método Trim no .NET Framework 3.5 SP1 e em versões anteriores não ajusta três caracteres de espaço em branco Unicode: SEPARADOR DE VOWEL MONGÓLIA (U + 180E), ESPAÇO NENHUMAS BREAK (U + 202F) E ESPAÇO MATEMÁTICO MÉDIO (U + 205F).

Eu tive alguns dados de teste incorretos, o que me causou alguma confusão. Com base em como evitar tropeçar na lista de materiais UTF-8 ao ler arquivos , descobri que isso funcionava:

 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; } 

Definir o cliente A propriedade de codificação reduz corretamente a BOM para um único caractere. No entanto, XDocument.Parse ainda não lerá essa seqüência de caracteres. Esta é a versão mais limpa que eu tenho até agora.

Isso funciona também

 int index = xmlResponse.IndexOf('< '); if (index > 0) { xmlResponse = xmlResponse.Substring(index, xmlResponse.Length - index); } 

Um método rápido e simples para removê-lo de uma string:

 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", ""); } 

Como usar:

 string yourCleanString=RemoveBom(yourBOMString); 

Eu tive um problema muito semelhante (eu precisava analisar um documento XML representado como uma matriz de bytes que tinha uma marca de ordem de byte no início dele). Eu usei um dos comentários de Martin em sua resposta para chegar a uma solução. Eu peguei o array de bytes que eu tinha (ao invés de convertê-lo em uma string) e criei um object MemoryStream com ele. Então eu passei para XDocument.Load , que funcionou como um encanto. Por exemplo, digamos que xmlBytes contenha seu XML na codificação UTF8 com uma marca de byte no começo dele. Então, esse seria o código para resolver o problema:

 var stream = new MemoryStream(xmlBytes); var document = XDocument.Load(stream); 

É simples assim.

Se começar com uma string, ela ainda deve ser fácil de fazer (suponha que xml seja sua string contendo o XML com a marca de ordem de byte):

 var bytes = Encoding.UTF8.GetBytes(xml); var stream = new MemoryStream(bytes); var document = XDocument.Load(stream); 

Eu escrevi o seguinte post depois de encontrar esse problema.

Essencialmente, em vez de ler os bytes brutos do conteúdo do arquivo usando a class BinaryReader, eu uso a class StreamReader com um construtor específico que remove automaticamente o caractere de marca de ordem de byte dos dados textuais que estou tentando recuperar.

Passe o buffer de byte (via DownloadData) para a string Encoding.UTF8.GetString(byte[]) para obter a string em vez de baixar o buffer AS como uma string. Você provavelmente tem mais problemas com seu método atual do que apenas aparar a marca de ordem de byte. A menos que você decodifique corretamente como sugerimos aqui, os caracteres unicode provavelmente serão interpretados incorretamente, resultando em uma string corrompida.

Edit : A resposta de Martin é melhor, já que evita alocar uma string inteira para XML que ainda precisa ser analisada de qualquer maneira. A resposta que dei melhor se aplica a seqüências gerais que não precisam ser analisadas como XML.

 StreamReader sr = new StreamReader(strFile, true); XmlDocument xdoc = new XmlDocument(); xdoc.Load(sr); 

Eu corri para isso quando eu tinha um arquivo codificado em base 64 para se transformar na string. Embora eu possa tê-lo salvo em um arquivo e, depois, lido corretamente, aqui está a melhor solução que consegui tirar do byte[] do arquivo para a string (Basicamente com base na resposta de 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); } } 

Onde StartsWith(byte[]) é a extensão lógica:

 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; }