6


3

まあ私はバイト配列を持っている、そして私はそのバイト配列内のそのxml serilizedオブジェクトを知っているそれからエンコーディングを取得する方法はありますか?

私はそれをdeserilizeするつもりはないが、SQLサーバー上のxmlフィールドにそれを保存しています…​ だから私はそれを文字列に変換する必要がありますか?

4 Answer


14


https://stackoverflow.com/questions/637855/how-to-best-detect-encoding-in-xml-file[この質問]のような解決策はバイト配列上のストリームを使用することによってこれを解決することができます。 そうすれば、バイトレベルでいじる必要がなくなります。 このような:
エンコーディングエンコーディング。 using(var stream = new MemoryStream(bytes)){using(var xmlreader = new XmlTextReader(stream)){xmlreader.MoveToContent(); encoding = xmlreader.Encoding; }}


8


最初の40バイトの^ 1 ^を見ることができます。 それらは、エンコードを含むドキュメント宣言(ドキュメント宣言と仮定)を含む必要があります_or_ UTF-8またはUTF-16であると想定できます。 (両方のパターンを確認してください。)+ `

現実的には、UTF-8またはUTF-16以外のものが手に入ると思いますか? そうでない場合は、両方のパターンの開始時に取得したパターンを確認し、どちらのパターンにも従わない場合は例外をスローします。 あるいは、別の試みをしたい場合は、常に文書をUTF-8としてデコードし、それを再エンコードして同じバイトを取り戻すかどうかを確認することができます。 理想的ではありませんが、うまくいくかもしれません。

これを行うにはもっと厳密な方法があると私は確信していますが、それらは細心の注意を払う必要があります:)

'' '' '

^ 1 ^これよりかなり小さいかもしれません。 私は20文字で十分なはずです、これはUTF-16では40バイトです。


7


最初の2バイトまたは3バイトは、ストリームがUTF-8、Unicode-LittleEndian、またはUnicode-BigEndianのいずれであるかを示すことができるByte Order Mark(BOM)です。

UTF-8 BOMは0xEF 0xBB 0xBFです。Unicode-Bigendianは0xFEです。0xFF Unicode-LittleEndiaonは0xFFです。0xFE

これらのいずれも存在しない場合は、ASCIIを使用して +をテストできます(ほとんどの最新のXML生成は、XML宣言の前に空白がないことが標準に準拠していることに注意してください)。 +

ASCIIは `+?> +`まで使用されるため、encoding =の存在とその値を見つけることができます。 エンコーディングが存在しない、または宣言が存在しない場合は、UTF-8と見なすことができます。


5


W3C XML specificationには、バイト文字列のエンコーディングの決定方法に関するセクションがあります。

Unicodeのバイトオーダーマークを最初にチェックする

BOMは単なる別の文字です。それは:

ファイル内の他のすべての文字とともに、文字* U FEFF *は、適切なエンコード方式を使用してエンコードされます。

  • * + 00 00 FE FF + *:UCS-4、ビッグエンディアンマシン(1234オーダー)

  • * + FF FE 00 00 + *:UCS-4、リトルエンディアンマシン(4321注文)

  • * + 00 00 FF FE + *:UCS-4、珍しいオクテット順(2143)

  • * + FE FF 00 00 + *:UCS-4、珍しいオクテット順(3412)

  • * + FE FF + *:UTF-16、ビッグエンディアン

  • * + FF FE + *:UTF-16、リトルエンディアン

  • * + EF BB BF + *:UTF-8

where `+ +`は何でも構いません-両方がゼロであることを除く

だから最初にそれらの署名のいずれかのための初期バイトをチェックしてください。 それらのうちの1つを見つけたら、それを戻しなさいhttps://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx?f=255

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)

それとも他を探す

XML文書にByte Order Mark文字が含まれていない場合は、次に、すべてのXML文書に含まれている必要がある最初の5文字を​​探します。

_ _ + +

それを知っておくと便利です

  • * + <+ *は#x0000003Cです

  • * *は#x0000003Fです

これで、最初の4バイトを見れば十分です。

  • * + 00 00 00 3C + *:UCS-4、ビッグエンディアンマシン(1234オーダー)

  • * + 3C 00 00 00 + *:UCS-4、リトルエンディアンマシン(4321注文)

  • * + 00 00 3C 00 + *:UCS-4、珍しいオクテット順(2143)

  • * + 00 3C 00 00 + *:UCS-4、珍しいオクテット順(3412)

  • * + 00 3C 00 3F + *:UTF-16、ビッグエンディアン

  • * + 3C 00 3F 00 + *:UTF-16、リトルエンディアン

  • * + 3C 3F 78 6D + *:UTF-8

  • * + 4C 6F A7 94 + *:EBCDICのフレーバー

それでは、コードにさらに追加することができます。

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

_ _