Pregunta

Bueno, yo tengo una matriz de bytes, y sé que es un objeto XML serilized en la matriz de bytes ¿Hay alguna manera de obtener la codificación de ella?

No voy a deserilize, pero im guardarlo en un campo XML en un servidor SQL ... por eso es necesario para convertirlo en una cadena?

¿Fue útil?

Solución

Se podría buscar en los primeros bytes 40-ish 1 . Ellos debe contiene la declaración de documento (suponiendo que tiene una declaración de documento) que debe contener o bien la codificación o se puede asumir que es UTF-8 o UTF-16, lo que debería debería ser obvio a partir de la forma en que has entendido la parte <?xml. (Sólo echa para ambos patrones.)

Siendo realistas, qué se puede esperar que usted conseguirá siempre que no sea UTF-8 o UTF-16 nada? Si no es así, se puede comprobar por los patrones que podemos encontrar en el inicio de ambas cosas y lanzar una excepción si no se sigue ya sea patrón. Alternativamente, si usted quiere hacer otro intento, siempre se puede tratar de decodificar el documento como UTF-8, volver a codificar y ver si se obtienen los mismos bytes de vuelta. No es lo ideal, pero podría funcionar.

Estoy seguro de que hay formas más rigurosas de hacer esto, pero son propensos a ser quisquillosos:)


1 Muy posiblemente menos que esto. I Figura 20 caracteres deben ser suficiente, que es de 40 bytes en UTF-16.

Otros consejos

Una solución similar a esta pregunta podría resolver este mediante el uso de una corriente sobre la matriz de bytes. A continuación, usted no tendrá que jugar a nivel de byte. De esta manera:

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

Los primeros 2 o 3 bytes pueden ser una marca de orden de bytes (BOM) que le puede decir si la corriente es UTF-8, Unicode o Unicode LittleEndian-BigEndian.

UTF-8 BOM es 0xEF 0xBB 0xBF Unicode es BigEndian 0xFE 0xFF Unicode-LittleEndiaon es 0xFF 0xFE

Si ninguno de estos están presentes, entonces se puede utilizar ASCII para la prueba de <?xml (nota más moderna generación de XML se pega a la norma de que ningún espacio en blanco puede preceder a la declare XML).

ASCII se utiliza hasta ?> para que pueda encontrar la presencia de encoding = y encontrar su valor. Si la codificación no está presente o declarar <?xml no está presente, entonces se puede asumir UTF-8.

El especificación XML de W3C tiene una sección sobre cómo determinar la codificación de una cadena de bytes.

En primer cheque por un byte Unicode marca de orden

Una lista de materiales es sólo otro carácter; que es la:

  

'CERO ANCHO NO-BREAK SPACE' (U + FEFF)

El carácter U + FEFF , junto con cada otro carácter en el archivo, se codifica utilizando el esquema de codificación apropiado:

  • 00 00 FE FF UCS-4, la máquina-big endian (1234 orden)
  • FF FE 00 00 : UCS-4, poco-endian máquina (4,321 orden)
  • 00 00 FF FE : UCS-4, orden octeto inusual (2143)
  • FE FF 00 00 : UCS-4, orden octeto inusual (3412)
  • FE FF ## ## UTF-16, bigEndian
  • FF FE ## ## UTF-16, ascendente hacia la izquierda
  • EF BB BF UTF-8

donde ## ## puede ser cualquier cosa - excepto por tanto siendo cero

Así que compruebe primero los bytes de mad por cualquiera de esas firmas. Si encuentra uno de ellos, de retorno que página de códigos 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)

o bien buscar

Si el documento XML tiene ninguna marca de orden de bytes de caracteres, entonces pasar a buscar los primeros cinco caracteres que cada documento XML debe tener:

  

<?xml

Es útil saber que

  • < es x0000003C #
  • ? es x0000003F #

Con que tenemos suficiente para mirar a los cuatro primeros bytes:

  • 00 00 00 3C UCS-4, la máquina-big endian (1234 orden)
  • 3C 00 00 00 : UCS-4, poco-endian máquina (4,321 orden)
  • 00 00 3C 00 : UCS-4, orden octeto inusual (2143)
  • 00 3C 00 00 : UCS-4, orden octeto inusual (3412)
  • 00 3C 00 3F UTF-16, bigEndian
  • 3C 00 3F 00 UTF-16, ascendente hacia la izquierda
  • 3C 3F 78 6D UTF-8
  • 4C 6F A7 94 un poco de sabor de EBCDIC

A continuación podremos agregar más a nuestro 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top