Pergunta

Bem, eu tenho uma matriz de bytes, e eu sei que é um xml serilized objeto na matriz de bytes é Existe alguma maneira de obter a codificação dele?

Eu não estou indo para deserilize-lo, mas estou salvando-o em um campo XML no servidor SQL ... então eu preciso convertê-lo para uma string?

Foi útil?

Solução

Você pode olhar para o primeiro 40-ish bytes 1 . Eles deve conter a declaração de documento (supondo que ele tem uma declaração de documentos) que deverá conter ou a codificação ou você pode assumir que é UTF-8 ou UTF-16, que deve deveria ser óbvio de como você já entendeu a parte <?xml. (Basta verificar para ambos os padrões.)

Realisticamente, você espera que você nunca vai conseguir nada diferente de UTF-8 ou UTF-16? Se não, você pode verificar os padrões que você começa no início de ambos os e lançar uma exceção se ele não segue qualquer padrão. Alternativamente, se você quiser fazer outra tentativa, você poderia sempre tentar decodificar o documento como UTF-8, re encode-lo e ver se você obter os mesmos bytes de volta. Não é o ideal, mas só poderia trabalhar.

Eu tenho certeza que existem formas mais rigorosas de fazer isso, mas eles são susceptíveis de ser mimado:)


1 Muito possivelmente menos do que isso. I Figura 20 caracteres deve ser suficiente, que é de 40 bytes no UTF-16.

Outras dicas

solução Um semelhante ao esta questão poderia resolver este usando um fluxo através da matriz de bytes. Então você não terá que mexer no nível de byte. Como esta:

Encoding encoding;
using (var stream = new MemoryStream(bytes))
{
    using (var xmlreader = new XmlTextReader(stream))
    {
        xmlreader.MoveToContent();
        encoding = xmlreader.Encoding;
    }
}

Os primeiros 2 ou 3 bytes pode ser um Byte Order Mark (BOM), que pode dizer se o fluxo é UTF-8, Unicode-littleEndian ou Unicode-bigEndian.

UTF-8 BOM é 0xEF 0xBB 0xBF Unicode-bigEndian é 0xFE 0xff Unicode-LittleEndiaon é 0xFF 0xFE

Se nenhum destes estão presentes, em seguida, você pode usar ASCII para teste para <?xml (nota mais modernas varas de geração de XML para o padrão que nenhum espaço em branco podem preceder a declarar xml).

ASCII é usado até ?> para que possa encontrar a presença de encoding = e encontrar o seu valor. Se a codificação não está presente ou <?xml declarar não está presente, então você pode assumir UTF-8.

O W3C XML especificação tem um seção sobre como determinar a codificação de uma seqüência de byte.

Primeira verificação para um Unicode Byte Order Mark

A BOM é apenas mais um caráter; é o:

'ZERO LARGURA NO ESPAÇO-BREAK' (U + FEFF)

O personagem U + FEFF , juntamente com todos os outros caracteres no arquivo, é codificado utilizando o esquema de codificação apropriada:

  • 00 00 FE FF : UCS-4, máquina big-endian (1234 ordem)
  • FF FE 00 00 : UCS-4, máquina little-endian (4321 ordem)
  • 00 00 FF FE : UCS-4, a fim octeto incomum (2143)
  • FE FF 00 00 : UCS-4, a fim octeto incomum (3412)
  • FE FF ## ## : UTF-16, big-endian
  • FF FE ## ## : UTF-16, little-endian
  • EF BB BF : UTF-8

, onde ## ## pode ser qualquer coisa - exceto para ambos sendo zero

Então, primeiro verifique os bytes inital por qualquer dessas assinaturas. Se você encontrar um deles, o retorno que código-página identificador

UInt32 GuessEncoding(byte[] XmlString)
{
   if BytesEqual(XmlString, [00, 00, $fe, $ff]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
   if BytesEqual(XmlString, [$ff, $fe, 00, 00]) return 1200;  //"utf-32" - Unicode UTF-32, little endian byte order
   if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 2143 UCS-4");
   if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
   if BytesEqual(XmlString, [$fe, $ff])
   {
      if (XmlString[2] <> 0) && (XmlString[3] <> 0)
         return 1201;  //"unicodeFFFE" - Unicode UTF-16, big endian byte order
   }
   if BytesEqual(XmlString, [$ff, $fe])
   {
      if (XmlString[2] <> 0) && (XmlString[3] <> 0)
         return 1200;  //"utf-16" - Unicode UTF-16, little endian byte order
   }
   if BytesEqual(XmlString, [$ef, $bb, $bf])    return 65001; //"utf-8" - Unicode (UTF-8)

Ou olhar mais para

Se o documento XML não tem caráter Byte Order Mark, então você passar a olhar para os cinco primeiros caracteres que cada documento XML deve ter:

<?xml

É útil saber que

  • < é # x0000003C
  • ? é # x0000003F

Com isso temos o suficiente para olhar para os primeiros quatro bytes:

  • 00 00 00 3C : UCS-4, máquina big-endian (1234 ordem)
  • 3C 00 00 00 : UCS-4, máquina little-endian (4321 ordem)
  • 00 00 3C 00 : UCS-4, a fim octeto incomum (2143)
  • 00 3C 00 00 : UCS-4, a fim octeto incomum (3412)
  • 00 3C 00 3F : UTF-16, big-endian
  • 3C 00 3F 00 : UTF-16, little-endian
  • 3C 3F 78 6D : UTF-8
  • 4C 6F A7 94 : algum sabor de EBCDIC

Assim, podemos então adicionar mais para o nosso código:

   if BytesEqual(XmlString, [00, 00, 00, $3C])    return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
   if BytesEqual(XmlString, [$3C, 00, 00, 00])    return 1200;  //"utf-32" - Unicode UTF-32, little endian byte order
   if BytesEqual(XmlString, [00, 00, $3C, 00])    throw new Exception("Nobody supports 2143 UCS-4");
   if BytesEqual(XmlString, [00, $3C, 00, 00])    throw new Exception("Nobody supports 3412 UCS-4");
   if BytesEqual(XmlString, [00, $3C, 00, $3F])   return return 1201;  //"unicodeFFFE" - Unicode UTF-16, big endian byte order
   if BytesEqual(XmlString, [$3C, 00, $3F, 00])   return 1200;  //"utf-16" - Unicode UTF-16, little endian byte order
   if BytesEqual(XmlString, [$3C, $3F, $78, $6D]) return 65001; //"utf-8" - Unicode (UTF-8)
   if BytesEqual(XmlString, [$4C, $6F, $A7, $94])
   {
      //Some variant of EBCDIC, e.g.:
      //20273   IBM273  IBM EBCDIC Germany
      //20277   IBM277  IBM EBCDIC Denmark-Norway
      //20278   IBM278  IBM EBCDIC Finland-Sweden
      //20280   IBM280  IBM EBCDIC Italy
      //20284   IBM284  IBM EBCDIC Latin America-Spain
      //20285   IBM285  IBM EBCDIC United Kingdom
      //20290   IBM290  IBM EBCDIC Japanese Katakana Extended
      //20297   IBM297  IBM EBCDIC France
      //20420   IBM420  IBM EBCDIC Arabic
      //20423   IBM423  IBM EBCDIC Greek
      //20424   IBM424  IBM EBCDIC Hebrew
      //20833   x-EBCDIC-KoreanExtended IBM EBCDIC Korean Extended
      //20838   IBM-Thai    IBM EBCDIC Thai
      //20866   koi8-r  Russian (KOI8-R); Cyrillic (KOI8-R)
      //20871   IBM871  IBM EBCDIC Icelandic
      //20880   IBM880  IBM EBCDIC Cyrillic Russian
      //20905   IBM905  IBM EBCDIC Turkish
      //20924   IBM00924    IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
      throw new Exception("We don't support EBCDIC. Sorry");
   }

   //Otherwise assume UTF-8, and fail to decode it anyway
   return 65001; //"utf-8" - Unicode (UTF-8)

   //Any code is in the public domain. No attribution required.
}

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top