tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re: COMP-3の変換につて
投稿日: 2017/09/22(Fri) 12:32
投稿者魔界の仮面弁士
ループカウンタすらローカル変数になっていないなど、
モジュールレベル変数(フィールド変数)を使いすぎな点が気にかかります。

また、COMP3_CNV_RTN の引数を ByVal にしていないのは何故でしょうか?


> MOTO = GT.W_200
> MOTO = StrConv(GT.W_200, vbFromUnicode) ' システムコードに変換
最初の代入は無意味に見えますし、同じ変数に使いまわして
Unicode 文字列と ANSI バイナリの両方を格納するのにも違和感があります。


> 正常値例
> 異常値例

正常に変換される例と、失敗する例の提示はありがたいですが、
失敗する方については「本来期待する結果」も併記してもらわないと
状況を理解しにくいです。

パック10進なので、末尾4bit が 0111 (&HC) なら "+"、1000 (&HD) なら "-" になるはずが、
末尾 c なのに負数判定されてしまうのが問題ということでしょうかね。
その他、データ部も差異があるようですが。


今回のケースは、そもそも変換元のデータを「文字列」として処理しようとしているのが間違いです。
渡すべきデータさえ破損していなければ、現状の COMP3_CNV_RTN の実装でも正しく変換されるようですし。

以下実験コード

=== Command1(Byte型の一次元配列) ===
000489944c --> +000489944
000009834c --> +000009834
000015048c --> +000015048
000007982c --> +000007982
000011439c --> +000011439
'=== Command2(String型) ===
000489944c --> +000489944
000009834c --> +000009834
000015048c --> -0000150481
000007982c --> -0000078145
000011439c --> -0000114381

Private Sub Command1_Click()
    Dim source() As String, src As Variant
    source = Split("000489944c 000009834c 000015048c 000007982c 000011439c")

    Debug.Print "'=== Command1(Byte型の一次元配列) ==="
    For Each src In source
        Dim bin5() As Byte
        bin5 = HexStringToBinary(src)
        Call COMP3_CNV_RTN((bin5), 5)  '
        Debug.Print src; " --> "; W_SIGN; Result
    Next
End Sub

Private Sub Command2_Click()
    Const japanese As Integer = &H411
    Dim source() As String, src As Variant
    source = Split("000489944c 000009834c 000015048c 000007982c 000011439c")

    Debug.Print "'=== Command2(String型) ==="
    For Each src In source
        Dim bin5() As Byte
        bin5 = HexStringToBinary(src)
        Dim GT_W_200 As String
        GT_W_200 = StrConv(bin5, vbUnicode, japanese)

        MOTO = StrConv(GT_W_200, vbFromUnicode, japanese)
        COMP3_CNV_RTN MOTO, 5
      
        Debug.Print src; " --> "; W_SIGN; Result
    Next
End Sub

Public Function HexStringToBinary(ByVal Text As String) As Byte()
    With CreateObject("Microsoft.XMLDOM").createElement("e")
        .DataType = "bin.hex"
        .Text = Text
        HexStringToBinary = .NodeTypedValue
    End With
End Function
'Public Function BinaryToHexString(ByRef Binary() As Byte) As String
'    With CreateObject("Microsoft.XMLDOM").createElement("e")
'        .DataType = "bin.hex"
'        .NodeTypedValue = Binary
'        BinaryToHexString = .Text
'    End With
'End Function


> 0x80以降のデータで正しく変換できたりできなかったり

単独バイナリでの 0x8c は、文字の割り当てが無いためです。

注意深く扱えば String 型に詰めて扱うことは可能ですが、B 系以外の関数を使ったり、
vbUnicode / vbFromUnicode 等で変換させてしまうと、データを破損させてしまうことになります。


下記に、文字集合ごとの定義範囲を示します。

【Windows コードページ 932 のバイナリ定義】
 0x00〜0x1F 「制御文字」
 0x20〜0x3F 「ASCII文字」
 0x40〜0x7E 「ASCII文字」「2 バイト文字の後続バイト」
 0x80〜0x80 「1 バイト文字の予約領域(未使用)」「2 バイト文字の後続バイト」
 0x81〜0x9F 「2 バイト文字の先導バイト」「2 バイト文字の後続バイト」
 0xA0〜0xA0 「1 バイト文字の予約領域(未使用)」「2 バイト文字の後続バイト」
 0xA1〜0xDF 「半角カタカナ」「2 バイト文字の後続バイト」
 0xE0〜0xFC 「2 バイト文字の先導バイト」「2 バイト文字の後続バイト」
 0xFD〜0xFF 「予約領域(未使用)」


【Shift_JIS のバイナリ定義】
 0x00〜0x1F 「制御文字」
 0x20〜0x3F 「ASCII文字」
 0x40〜0x7E 「ASCII文字」「2 バイト文字の後続バイト」
 0x80〜0x80 「1 バイト文字の予約領域(未使用)」「2 バイト文字の後続バイト」
 0x81〜0x9F 「2 バイト文字の先導バイト」「2 バイト文字の後続バイト」
 0xA0〜0xA0 「1 バイト文字の予約領域(未使用)」「2 バイト文字の後続バイト」
 0xA1〜0xDF 「半角カタカナ」「2 バイト文字の後続バイト」
 0xE0〜0xEF 「2 バイト文字の先導バイト」「2 バイト文字の後続バイト」
 0xF0〜0xFC 「未定義領域」
 0xFD〜0xFF 「予約領域(未使用)」



次に、データが破損していた仕組みを解説します。


> 異常値例
> 0x00 00 15 04 8c --> -0000150481
00 は「制御文字 Null」1文字目
00 は「制御文字 Null」2文字目
15 は「制御文字 Shift In」3文字目
04 は「制御文字 End of Transmission」4文字目
8c は「2 バイト文字の先導バイト」5文字目の前半

→ 後続バイトが欠落しているとみなされ、5 文字目は代替文字 "・" に置き換わります。
 "・" は 0x8145 (Unicode だと U+30FB)相当の文字なので、
 最初の 4 バイトまでは 00,00,15,04 と期待通りに変換されたものの、
 末尾の 5 バイト目が 81 と判断されたのでしょう。
→ちなみに Len(StrConv(HexStringToBinary("000015048C"), vbUnicode)) は「5」文字です。


> 異常値例
> 0x00 00 07 98 2c --> -0000078145
00 は「制御文字 Null」1文字目
00 は「制御文字 Null」2文字目
07 は「制御文字 Bell」3文字目
98 は「2 バイト文字の先導バイト」4文字目の前半
2c は「ASCII 文字 ","」破損データ

→ 98 の後に 2c が来ることは想定されていないため、4 文字目が代替文字 "・" に置き換わります。
 これは 0x8145 (Unicode だと U+30FB)相当の文字なので、
 最初の 3 バイトまでは 00,00,07 と期待通りに変換されたものの、
 末尾に 8145 が付与されているのでしょう。
→ ちなみに Len(StrConv(HexStringToBinary("000007982C"), vbUnicode)) は「4」文字です。


> 異常値例
> 0x00 00 11 43 9c --> -0000114381
00 は「制御文字 Null」1文字目
00 は「制御文字 Null」2文字目
11 は「制御文字 Vertical Tabulation」3文字目
43 は「ASCII文字 "C"」4文字目
9c は「2 バイト文字の先導バイト」5文字目の前半

→ 後続バイトが欠落しているとみなされ、5 文字目が代替文字 "・" に置き換わります。
→ ちなみに Len(StrConv(HexStringToBinary("000011439C"), vbUnicode)) は「5」文字です。



> 正常値例
> 0x00 04 89 94 4c --> +000489944
00 は「制御文字 Null」1文字目
04 は「制御文字 End of Transmission」2文字目
89 は「2 バイト文字の先導バイト」3文字目の前半
94 は「2 バイト文字の後続バイト」3文字目の後半 … 3文字目は "鉛"
4c は「ASCII文字 "L"」4文字目

→ 文字列欠損なく、ANSI/Unicode 変換が可能です。
→ ちなみに Len(StrConv(HexStringToBinary("000489944C"), vbUnicode)) は「4」文字です。


> 正常値例
> 0x00 00 09 83 4c --> +000009834
00 は「制御文字 Null」1文字目
00 は「制御文字 Null」2文字目
09 は「制御文字 Horizontal Tabulation」3文字目
83 は「2 バイト文字の先導バイト」4文字目の前半
4c は「2 バイト文字の後続バイト」4文字目の後半 … 4文字目は "キ"

→ 文字列欠損なく、ANSI/Unicode 変換が可能です。
→ ちなみに Len(StrConv(HexStringToBinary("000009834C"), vbUnicode)) は「4」文字です。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。