DOBON.NETプログラミング道掲示板

No34084 の記事


■34084 / )  Re[1]: 文字列を8bit に戻してから UTF-8 に変換する方法
□投稿者/ 魔界の仮面弁士 大御所(1186回)-(2019/01/07(Mon) 11:55:41)
  • アイコンNo34079に返信(satoさんの記事)
    > Dim str1 As String=「あるDLL("漢字")」
    > Dim bytesData As Byte() = System.Text.Encoding.UTF8.GetBytes(str1)
    > Dim str2 As String = System.Text.Encoding.UTF8.GetString(bytesData)

    Imports System.Text
    Imports System.IO
    Module Module1
     Sub Main()
      ' ここはテスト用のコードなので無視して OK
      Dim chars(5) As Char
      chars(0) = ChrW(&H00E6) 'U+00E6: Latin Small Letter Ae
      chars(1) = ChrW(&H00BC) 'U+00BC: Vulgar Fraction One Quarter
      chars(2) = ChrW(&H00A2) 'U+00A2: Cent Sign
      chars(3) = ChrW(&H00E5) 'U+00E5: Latin Small Letter A with Ring Above
      chars(4) = ChrW(&H00AD) 'U+00AD: Soft Hyphen (SHY)
      chars(5) = ChrW(&H0097) 'U+0097: <End of Guarded Area> (EPA)

      Dim str0 As String = New String(chars)
      MsgBox(str0, vbInformation)

      'Dim str1 As String=「あるDLL("漢字")」の代用
      Dim str1 As String = Encoding.Unicode.GetString(New Byte() {&HE6, &H0, &HBC, &H0, &HA2, &H0, &HE5, &H0, &HAD, &H0, &H97, &H0})

      'str0 と str1 が同じ文字列であることの確認
      MsgBox(str0.Equals(str1))

      'ファイルとして吐き出してみる
      Using writer As New StreamWriter("D:\utf-8.txt")
       writer.Write(str1)
       writer.Close()
      End Using
      Using writer As New StreamWriter("D:\utf-16.txt", False, New UnicodeEncoding(False, False))
       writer.Write(str1)
       writer.Close()
      End Using
      Using writer As New StreamWriter("D:\utf-16BE.txt", False, New UnicodeEncoding(True, False))
       writer.Write(str1)
       writer.Close()
      End Using


      '★ 本題:これでどうでしょう ★
      Dim str2 As String = Encoding.UTF8.GetString(str1.Select(Function(c) CByte(AscW(c))).ToArray())
      MsgBox(str2, vbInformation) '「漢字」
     End Sub
    End Module




    No34081に返信(satoさんの記事)
    > Using writer As StreamWriter = New StreamWriter("ファイル名.txt")
    > writer.Write(str1)
    上記の構文では、変数 str1 は As String または As Char() であり、
    かつ、StreamWriter は BOM 無しの UTF-8 エンコードであることを意味しますね。

    だとしたら
    > 00 e6 00 bc 00 a2 00 e5 00 ad となるということです。
    これはありえないはず。(末尾の 00 97 が欠落している点を抜きにしても)


    もしも本当に UTF-8 として保存された文字列データだとしたら、バイナリとしてみた際に
    &HE6 の後ろには &H80〜&HBF の範囲のバイナリが 2 つなければなりません。

    UTF-8 においては、各バイトの最上位ビットでマルチバイト文字かどうかが判断されるためです。
     U+0000〜U+007F は 00000000,0xxxxxxx → 1 バイト文字: &B0xxxxxxx
     U+0080〜U+07FF は 00000xxx,xxyyyyyy → 2 バイト文字: &B110xxxxx, &B10yyyyyy
     U+0800〜U+FFFF は xxxxyyyy,yyzzzzzz → 3 バイト文字: &B1110xxxx, &B10yyyyyy, &B10zzzzzz
    U+10000〜U+1FFFFFは 00000000,000wwwxx,xxxxyyyy,yyzzzzzzz → 4 バイト文字: &B11110www, &B10xxxxxx, &B10yyyyyy, &B10zzzzzz



    Imports System.Text
    Module Module1
     Sub Main()
      Dim rawBinary1 As Byte() = {&H0, &HE6, &H0, &HBC, &H0, &HA2, &H0, &HE5, &H0, &HAD, &H0, &H97}
      Dim rawBinary2 As Byte() = {&HE6, &H0, &HBC, &H0, &HA2, &H0, &HE5, &H0, &HAD, &H0, &H97, &H0}

      Dim enc1 = Encoding.GetEncoding("UTF-8", New EncoderExceptionFallback(), New DecoderExceptionFallback())
      Dim enc2 = Encoding.GetEncoding("UTF-16LE", New EncoderExceptionFallback(), New DecoderExceptionFallback())
      Dim enc3 = Encoding.GetEncoding("UTF-16BE", New EncoderExceptionFallback(), New DecoderExceptionFallback())

      For Each enc In {enc1, enc2, enc3}
       Console.WriteLine(enc.BodyName)
       For Each binary In {rawBinary1, rawBinary2}
        Try
         Console.WriteLine(enc.GetString(binary))
        Catch ex As DecoderFallbackException
         '★ UTF-8 として解釈すると、E6 の部分でデコードに失敗してしまう ★
         Console.Error.WriteLine(ex.Message)
        End Try
       Next
       Console.WriteLine("-------------")
      Next
      Console.ReadKey()
     End Sub
    End Module



    > 「あるDLL」を用いて"漢字" という文字列を取得すると、00e6 00bc 00a2 00e5 00ad 0097 と 16bit 化してstring変数に格納しています。
    > 「あるDLL」(の関数)で返される文字列は、UTF-8 の 8bit データを UTF-16 の 16bit データとした文字列、という説明で伝わりますでしょうか?
    "漢字" を UTF-8 でエンコードすると E6 BC A2 E5 AD 97 なので、それを 16bit 化しているわけですね。


    × StreamWriter で (既定の) UTF-8 として出力したときに「00 e6 00 bc 00 a2 ……」になる
    × StreamWriter で UTF-16 として出力したときに「00 e6 00 bc 00 a2 ……」になる
    ○ StreamWriter で UTF-16 として出力したときに「e6 00 bc 00 a2 00 ……」になる
    ○ StreamWriter で UTF-16 として出力したときに「00e6 00bc 00a2 ……」になる
違反を報告
返信 削除キー/


Mode/  Pass/


- Child Tree -