[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『数値表現変換について』(フェンダー)
下記にプログラムで
パック10進数からゾーン10進数に変換出来るように
なってます。
これをバイナリからゾーンに
変換するのにうまくいきません。
ちなみに元のパックは5バイトで
変換後は10バイトから1バイト減らしてます。
達成 パック→5バイトをゾーン9バイトに変換
j(1 To 5) As Byte
In = In + 5
Out = OutPOS + 9
プログラム内容はすべて記載してません。
課題 バイナリ→2バイトをゾーン4バイトに変換
どなたかバイナリに詳しいかたアドバイスください。
よろしくお願いいたします。
Dim ArrySize As Long
Dim dSize As Long
Dim 符号 As Byte
Dim up As Long
Dim sup As String
Dim down As Long
Dim sdown As String
Dim tmp As String
ArrySize = UBound(B1) dSize = ArrySize * 2 - 1
tmp = "" For i = 1 To ArrySize ' For Each i In B1 ArrySize = ArrySize + 1
up = Int(B1(i) / 16) sup = D2H(CInt(up))
down = B1(i) Mod 16 sdown = D2H(CInt(down))
tmp = tmp & CStr(sup) & CStr(sdown) Next i tmp = Mid(tmp, 1, dSize)
エクセル2010 フェンダー
オフコン時代には、私も使っていたデータ型です。 私等は、このゾーン10進数は、アンパック型と学びましたが・・・。
それはさておき
>バイナリ→2バイトをゾーン4バイトに変換
このゾーン4バイトとは、4バイトのゾーン10進数に変換 ということですか?
そうだとしたら、まず、例を示してください。
バイナリー &h100 ----->ゾーン4バイトでは、??? バイナリー &h7fff ----->ゾーン4バイトでは、???
ちがうのなら、この辺りを説明してください
ichinose
全面的に寝ぼけていたようなのでいったん書き込みを削除します。失礼。
顔を洗って、仕切り直し。
1バイトずつに区切ったものを x とすると、その x は 0 〜 255 までの値なので以下のようにすると それぞれの上位4ビットの値と下位4ビットの値が取り出せないかなぁ? (まだ寝ぼけているかもしれないけど) その1バイトずつに区切った、最終バイトの下位4ビットは 12,13,15 あたりになるんだろうね。
Sub test() Dim x
x = &H89
MsgBox Int(x / 16) MsgBox x - Int(x / 16) * 16 'あるいは MsgBox x And &HF
x = &H5F
MsgBox Int(x / 16) MsgBox x - Int(x / 16) * 16 'あるいは MsgBox x And &HF
End Sub
(ぶらっと)
>このゾーン4バイトとは、4バイトのゾーン10進数に変換
ということですか?
そうです。4バイトのゾーン10進数になります。
私も知識不足なのですが例えば
080Cのようなデータにあったとしたら
例 バイナリ10進数からゾーン10進数の変換
改造前 080C
改造後 8C
私の認識が合っていればこのようなイメージです。
考え方がおかしければご指摘ください。
(フェンダー)
>そうです。4バイトのゾーン10進数になります。 だとしたら・・・・、
>改造前 080C >改造後 8C
少なくともこれは、違います。
http://www.jtw.zaq.ne.jp/kayakaya/new/kihon/text/zonepack.htm
上記にパック・アンパック(ゾーン10進数) の説明があります。
これからすると、アンパック型の下位ハーフバイトには、0〜9しか入らないのです。
これからすると、&H8Cとはなりませんね!!
ここを良く調べてください。
実は、そうなるとまだ問題があります。
2バイトバイナリデータって、つまりVBAでいうInteger型の変数です。
これの値の許容範囲って いくつだと思いますか?
4バイトのゾーン10進数、4バイトでは収まりきらないと思いますよ!!
調べてみてください。
ichinose@今から、もろこし焼き
今、外出から帰って、あらたてて自分がアップしたレスをみると、随分滑ってましたなぁ。 無視してください。
ところで バイナリー10進 という言葉自体、私にはよくわからないものなので イメージしているのとは異なっているのかもしれないんだけど、大昔我々がホストで使っていたものは データを16進であらわすと、たとえば12345なら
Zoned Decimal F1F2F3F4F5 (コードはIBMホスト用) の5Byes Packed Decimal 12345C の 3Bytes
で上記 12345C を ichinoseさんもいわれた【UnPack】を行うと F1F2F3F4C5 と、最後の桁のゾーン部分が IBM では F ではなく C になるので、Zoned Decimal において Zone部分が F ではなく C も正の数と扱う。
で、今回のスレ主さんのテーマは、今もある、そういったPaced Decimal のデータをどこかから、 エクセルVBAで扱うことのできる媒体にして取り込み、それをVBAで Zoned Decimal 形式に 変換することだと思っていたんだけど、そうじゃなかったのかな?
(ぶらっと)
私がオフコン時代に扱っていたアンパック型データは、前回のリンク先で示されるデータ構造と 殆ど同じでした。殆どと言うのは、符号部分は、うろ覚えなので、なんせ25年前ですから・・・。
数字の12345をアンパック形式で表すと・・・、
31323334c5 という5バイトになります。符号部を除けば、文字列の数字ですから、 実は、殆ど私は、使っていませんでした。
本当は、入力データに対し、出力データを例を交えて説明された方がよいです。
>バイナリ10進数からゾーン10進数の変換
私の解釈は・・・。
2バイトデータに 80cだとすると・・・、
Sub test1() Dim x As Integer x = &H80C MsgBox x End Sub
上記コードを実行すれば Hexの80Cが 10進数のい2060だと分かります。
よってこれをアンパック型に変換すれば(私の扱っていた形式では)、
323036c0 の4バイトになる と言う解釈でした。
が、こうなると2バイトデータは、正の数の限界は、32767ですから、4バイトでは、足りない と言うことだったのです。
まずここの入力データと出力データをはっきりさせる事ですよ。
はっきりすれば、パック形式からアンパック形式の変換が出来た方ですから、 たぶん、御自分で解決できることだと思います。
ichinose@焼きもうろこし5本で満腹
変換することだと思っていたんだけど、そうじゃなかったのかな?
ほかには下記のようなプログラムはVBAで組んでます。
1_16進数で入力された数字を、0〜Fで返す
2_ UNICODE文字列をUTF8文字列に変換する
3_ UNICODE文字列をEBCDIC文字列に変換する
文字コード2バイト(KEIS)1バイト(EBCDIC)文字が
混在したデータに対してパック型・バイナリ型の領域を含んだ
データをバイナリ入出力して
それをCSV変換してデータとして扱ってます。
現状のプログラムだとパック10進数領域の部分は文字と
認識されるのですが
バイナリ領域が文字化けをおこしてます。
ちなみにCells関数でバイナリ入出力する際
パック型・バイナリ型両方ともに、セルには
データとしてほしい文字はゲットできてますが
バイナリデータ自体のプログラムがだめなようです。
(フェンダー)
>本当は、入力データに対し、出力データを例を交えて説明された方がよいです。
現在データ自体がありませんので
またあらためてご説明させていただきます。
別の視点からのヒントのようなものから開発作業が進むと思われますので
ちょっとした情報でも助かります。
長期戦になりそうですがよろしくお願いします。
(フェンダー)
テーマとははずれるけど、アンパックされた数字のゾーン部分、私がアップしたのはコメントしたように IBMホスト等のEBCDICコード体系で、一方 ichinoseさんのご紹介(ゾーン部分が 3)はASCII系。 懐かしくなってコメントアップ。失礼。
(ぶらっと)
途中報告をさせて頂きます。
冒頭で話しました
コードで
PSize = ArrySize * 2 - 1の
- 1を取り
BSize = ArrySize * 2
のフラッグを立て
入出力しましたら
文字として認識するようになりました。
バイナリ10進数2byte変換前 0050
ゾーン10進数時4byte変換後 F0F0F5F0
数値にすると0060になります。
ですがこのプログラムですと
ゾーン10進数時4byte変換後の文字が003や000など
レコードによって3桁表示になってしまいます。
因みにcells関数でチェックしますと
3桁領域のところには
003Fや000Fと後ろにFが付いてくる場合があります。
これだけ解消されれば
とりあえず解決するのですが・・・
(フェンダー)
(フェンダー)
>バイナリ10進数2byte変換前 0050 >ゾーン10進数時4byte変換後 F0F0F5F0 10進数2byteというのは、2バイトのパック型(符号なし)で ゾーン10進数時4byteといのは、 アンパック型(符号なし)又は、EBCDICコードの数字
というように考えられますが、 >数値にすると0060
これがわかりません。 0050 ですけどねえ・・・・、0060と言う結果が正しい結果なのですか?
これが正しい結果なら、
このようになる VBAコードが作成してあるなら、全部再現できるコードを提示してください。
0050(Hex) ------------- F0F0F5F0(Hex)-----------------これが 0060(10進数)と表示される
というコードを作ってあるんですよね?
見せてください。
ichinose
>これがわかりません。 0050 ですけどねえ・・・・、0060と言う結果が正しい結果なのですか?
大変失礼いたしました。0050です。
バイナリエディタでチェックする場合、他のデータも交じってますので・・・
パック型10進数からゾーン10進数のプログラムは100%合ってます。
なぜならテストに合格しているからです。
今回はそのプログラムをちょっといじって代用しただけなので・・・
ですのでバイナリの知識が分かれば解決すると思います。
現在のバイナリ領域をゾーン領域に数値変換した部分を
テキストにした数値ですのでご確認ください。
(フェンダー)
と各フィールドごとに分けまして
Get #InFN, InPOS, B型_1
tmpStr = B2D2(B型_1)
ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4
このようにフィールドごとに管理します。
それに加えて下記のような
コードから変換プログラムを加えます。
Function B2D2(B1() As Byte) As String
Dim ArrySize As Long
Dim dSize As Long
Dim 符号 As Byte
Dim 上位桁 As Long
Dim s上位桁 As String
Dim 下位桁 As Long
Dim s下位桁 As String
Dim tmp As String
ArrySize = UBound(B1) dSize = ArrySize * 2
tmp = "" For i = 1 To ArrySize
ArrySize = ArrySize
上位桁 = Int(B1(i) / 16) s上位桁 = D2H(CInt(上位桁))
下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁))
tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize)
B2D2 = tmp
End Function
あとは上位桁・下位桁を0〜Fにするイメージです。
ichinoseさんならだいたいこれでなにをしてるかお分かりになるとおもいます。
(フェンダー)
00(10進)=00(16進) 06(10進)=06(16進) 80(10進)=50(16進) 63(10進)=3F(16進) 17(10進)=11(16進) 現状は16進になっていますね。で、A〜Fが化けてていると。 D2Hのコードがないので確認できませんが、D2Hからは正しい結果が戻っていますか。 (cai)
追加 あと、chg_str2byteも確認。
Case 10
D2H = "A" Case 11 D2H = "B" Case 12 D2H = "C" Case 13 D2H = "D" Case 14 D2H = "E" Case 15 D2H = "F" Case Else D2H = CStr(itmp)
追加はこんな感じです。
Dim iSize As Long
iSize = Len(uniStr)
chg_str2byte = 1
i = 0 Do While (i < iSize) Select Case Mid(uniStr, i + 1, 1) Case "0" tmpByte(i + 1) = 240 Case "1" tmpByte(i + 1) = 241 Case "2" tmpByte(i + 1) = 242 Case "3" tmpByte(i + 1) = 243 Case "4" tmpByte(i + 1) = 244 Case "5" tmpByte(i + 1) = 245 Case "6" tmpByte(i + 1) = 246 Case "7" tmpByte(i + 1) = 247 Case "8" tmpByte(i + 1) = 248 Case "9" tmpByte(i + 1) = 249 End Select i = i + 1 Loop
(フェンダー)
断片のコードでよくわかりませんが、 パック型10進数からの変換プログラムを元にしたとのことで、 多分原因がわかりました。 変換できるのは0〜9だけで、あとはうまく変換できていないのでは? A〜Fを変換する部分がないのでしょう。追加していますか。 (cai) ああ、誤解を招きそう。 A〜Fの部分を追加するだけではダメです。 値の持ち方が違うので、0〜9の部分もパック型用から変更する必要があります。
アドバイスありがとうございます。 調べながら検証してみます。 バイナリ型って下記の説明のように 二進化十進表現BCD(Binary-coded decimal) コードのことなのでしょうか?
文字データや10進数との対応が取りやすいように、 10進数の0〜9に対応した4ビットの2進数で 10進数の各桁を表現する方法をBCDコード (Binary Coded Decimal code:2進化10進コード)という。
BCDコードでは、4ビットを単位として
0000〜1001(2進数)までの0〜9(10進数)に対応させて、 1011〜1111は使用しない。
10真数の桁数に合わせて2進数の桁数も変化する可変長形式の表現である。
(フェンダー)
それは(それが、かな)パック10進数です。 (cai)
>バイナリ型って下記の説明のように >二進化十進表現BCD(Binary-coded decimal) >コードのことなのでしょうか?
あらっ、これを御存知のうえの話ではないのですか?
もう一度、話を整理しませんか?
質問の概要が
>バイナリ→2バイトをゾーン4バイトに変換
これでしたね? 私が知りたかったのは、途中が欠けた再現できないコードではなく、
xxxという入力データに対し、プログラム実行後に YYYYYという出力結果
このデータ例を複数個、知りたかったのです。
ただ、これがここまでの投稿ではっきりしないのです。
最初私は、この2バイトのバイナリデータとは、VBAのInetger型のデータの事だと予想していました。 ですから、
>Sub test1() > Dim x As Integer > x = &H80C > MsgBox x >End Sub
>上記コードを実行すれば Hexの80Cが 10進数のい2060だと分かります。
という記述をしました。この2060と言う数字をアンパック型又は、文字列に変換すればよい と言うことだったのですが・・・。
途中、フェンダーさんから、
>バイナリ10進数2byte変換前 0050 >ゾーン10進数時4byte変換後 F0F0F5F0 >数値にすると0060になります。 (その後、0060は、0050だと訂正されました)
という投稿をされましたね?
私は、これを入力データに対し、結果として、出したいデータ例だと解釈しました。
この例からすると、入力データである2バイトのデータって、 2バイトのバック型のデータだと解釈できます。 >003Fや000Fと後ろにFが付いてくる場合があります。
これは、最後のハーフバイトがゾーンか否かの判断が必要なのだと思っていました。
例えば
2バイトのデータが 1230 ならば、f1f2f3f0 で1230と解釈
2バイトのデータが 003f ならば、f0f0f3 で003と解釈
これは
dim バイト(1 to 2) as byte
バイト(1)=0 バイト(2)=&h3F
if バイト(2) and &h0f>9 then Msgbox "ゾーンあり" else msgbox "ゾーンなし" end if
この程度の判断でよいかな?
と思っていました。
ところが・・・・。
現状 希望 50 80 50 80 50 80 50 80 50 80 50 80 50 80 50 80 0 0 50 80 50 80 50 80 3 63 11 17 0 15 16 22 14 20 13 19 0 15 12 18
これが入力データに対する希望の結果なのですか? (3----63、0----15 これも正しいのですか?これに関しては、説明がほしいです)
そうだとすれば、例外であげた二つを除けば、これは、最初に記述した
>Sub test1() > Dim x As Integer > x = &H80C > MsgBox x >End Sub
この考え方と一緒です。
入力データと出力データの関係がまだわかりません。
xxxという入力データに対し、プログラム実行後に YYYYYという出力結果
このデータ例を複数個、知りたいのです。
ichinose
>xxxという入力データに対し、プログラム実行後に YYYYYという出力結果
このデータ例を複数個、知りたかったのです。
途中が欠けた再現できないコードではなく、バイナリ入出力での実行前と実行後の値の
データ例でよろしいでしょうか??
そうであればテスト用のDATデータを作成して実行前実行後の値をすべて提示します。
(フェンダー)
バイナリ入出後は次のような結果になります。
F1 F2 F3 F4 F0 F0 F3 00 F0 F0 F0 F4 F0 F0 F5 F0 F0 F0 F1 F0 F0 F0 F0 F0 00 F5 00 F5 00 F0 00 F7 F0 F0 F0 F9 00 F0 00 F0
(フェンダー)
それは現状のコードでの結果ですか? 希望する結果はどうなりますか。 (cai)
>それは現状のコードでの結果ですか?
前レスで記載した通り今のプログラムということになります。
>希望する結果はどうなりますか。
たとえばバイナリ型の0050の数値があったとします。 10の値が16(進数)で表したとすると 20の値が32(進数)になると思います。 そうなると50の値の場合は80になりますよね? その考え方で希望する結果は計算できると思いますが 違いますでしょうか??
>それは(それが、かな)パック10進数です。
指摘されて色々と調べたのですが 二進化十進表現BCD(Binary-coded decimal)は バイナリではないにしろ パック10進数の事ではないんじゃないのでしょうか?? 私の考え方がおかしければご指摘ください。
(フェンダー)
希望数値というよりは
それが私の考えから算出した希望結果ではなくて
ユーザーからこうならなきゃいけないと
指摘された
答えになります。
0080
0080
0080
0080
0080
0080
0080
0080
0000
0080
0080
0080
0063
0017
0015
0022
0020
0019
0015
0018
0004
0000
0004
0005
(フェンダー)
上のテストデータ20byte 12 34 00 3F 00 04 00 50 00 10 00 00 F5 F5 F0 F7 00 09 F0 F0 の希望する変換結果を教えてください。 もしくは、その指摘された答えになる入力データの方を教えてください。
BCDはこちらが参考になるでしょうか。 -- 基礎から学ぶコンピュータ -- 《第六十号》 http://rryu.sakura.ne.jp/compfund/backnumber/compfund060.txt (cai)
>希望する変換結果を教えてください。
えっとですね。
イメージとして提示しましたが
私は把握してないかぎり
すいませんがテストケースはありえない数値も
加えていると思います。
下記のような数値が正しいです。
バイナリ型 0007 バイナリ入出力後の正しい数値 F0F0F0F7
バイナリ型 0012 バイナリ入出力後の正しい数値 F0F0F1F8
バイナリ型 0010 バイナリ入出力後の正しい数値 F0F0F1F6
バイナリ型 0020 バイナリ入出力後の正しい数値 F0F0F3F2
バイナリ型 0030 バイナリ入出力後の正しい数値 F0F0F4F8
バイナリ型 0040 バイナリ入出力後の正しい数値 F0F0F6F4
バイナリ型 0050 バイナリ入出力後の正しい数値 F0F0F8F0となっていきます。
ただしこれは提示された数値から逆算して
出した答えですので
計算ミスしている可能性もございます。
因みに二進化十進表現BCD(Binary-coded decimal)がパック10進数の事であれば
バイナリ型について詳しく記載されているサイトはご存知でしょうか??
(フェンダー)
http://mkt.blog8.fc2.com/blog-entry-12.html
(フェンダー)
>12 34 00 3F 00 04 00 50 00 10 00 00 F5 F5 F0 F7 00 09 F0 F0
この入力データは、実際のデータですか?
これらを2バイトずつ取り出して、アンパック4バイトに変換する
ということですか?
しかも、
>バイナリ型 0012 バイナリ入出力後の正しい数値 F0F0F1F8
このような変換をしたいなら、20バイトの最後の2バイトである F0F0は、どのような 結果が正しいのですか?
バイナリ型・・・、COBOLには、BINARY(COMP)というデータ型があったと思います。
おおよそ VBAのInteger型でよかったと思います。
上記の正しい結果を提示してほしいのですが・・・・。
>バイナリ型 0012 バイナリ入出力後の正しい数値 F0F0F1F8
こんな変換でいいなら
Sub smp1() Dim g0 As Long Dim binary(1 To 2) As Byte Dim resalt As Variant Dim dsp As String binary(1) = 0 binary(2) = &H12 resalt = cnvBtoUnp(binary()) dsp = "" For g0 = 1 To 4 dsp = dsp & Hex(resalt(g0)) Next MsgBox dsp End Sub Function cnvBtoUnp(b() As Byte) As Variant Dim ans(1 To 4) As Byte Dim cnstr As String Dim g0 As Long Dim g1 As Long g1 = 4 cnstr = CStr(b(1) * 2 ^ 8 + b(2)) g1 = Len(cnstr) For g0 = 4 To 1 Step -1 ans(g0) = &HF0 If g1 > 0 Then ans(g0) = ans(g0) + CInt(Mid(cnstr, g1, 1)) End If g1 = g1 - 1 Next cnvBtoUnp = ans() Erase ans() End Function
こんなコードで取得できます。
ichinose
>12 34 00 3F 00 04 00 50 00 10 00 00 F5 F5 F0 F7 00 09 F0 F0
このデータは私自身が適当に作成したデータですので
バイナリ型でF0F0などというデータ自体ありえない数値になるかもしれないので
忘れてください。
>これらを2バイトずつ取り出して、アンパック4バイトに変換する
ということですか? そういうことになるかと思います。
基本的な算出方法はおそらくこうです。
0050の場合なら10の位の5に16をかけて80となりF0F0F8F0
0012の場合なら10の位の1に16をかけて16+2でF0F0F1F8という感じかと思われます。
コードの提示ありがとうございます、
ちなみに今のプログラムにバイナリ型からアンパック型
変換できるコードを加えたいのですが
ichinoseさんは、サンプル提示をチェックされて どんなことを把握してコードを書かれたのでしょうか?? 考え方が分かれば参考にしたいのですが・・・
(フェンダー)
>昔のプログラマーの方は使用されていたようですね。 あはは、昔の・・か、でも、今もCOBOLで生業を立てている方もいるんですよ!! ちょっと前にCOBOL人口が増えているような話を聞いたことがあります。
>どんなことを把握してコードを書かれたのでしょうか?? 基本的には、フェンダーさんの考え方と同じですよ、
ファイルから読み込んだ2バイトのバイナリデータが Byte型変数二つに分けられて格納されています。
この二つのByte型変数から、求めるべきバイナリデータを10進数で取得し、得られた10進数をアンパック型に 再構築し、4バイトのデータを4つのByte型変数に分けて格納する。このデータをファイルに書き込む
例
バイナリデータ 1234 (16進数)
これが 二つのByte型変数に分けられたものが入力データです。
dim a as byte '上位1バイト dim b as byte '下位1バイト
a=&h12 b=&h34
が、この時点では
12(16進数) 34(16進数)
という二つの数字が与えられているだけですよね?
ここから 1234(16進数)という4桁の16進数を作成しなければならないのですよね?
&H12 &H34
&H12の桁を上げなければなりません。
10進数なら、12*100+34 と言う計算でよいのですが、16進数ですから、
&h12*16^2+&h34 となります。
前回提示のコード内で
b(1) * 2 ^ 8 + b(2) こんな式を記述しましたが、ビット単位に桁上げすると意味的には2^8ですが、 結果は、16^2と同じですよね? 2^8=16^2 ですから・・・。
でも、16進で表記するのですから 16^2 か &h100と記述した方がよかったかなあ
いずれにせよ
&h12*16^2+&h34 この計算から 4660(10進数)と言う結果を得ることが出来ます。
後は、アンパック型に加工すれば、よいですよね
前回投稿のコードをちょっと変更
Sub smp() Dim bb(1 To 2) Dim unp(1 To 4) As Byte Dim g0 As Long Dim ans As String bb(1) = &H12 bb(2) = &H34 Call cnvBtoUnp(bb(1), bb(2), unp()) For g0 = 1 To 4 ans = ans & Hex(unp(g0)) Next MsgBox ans End Sub Sub cnvBtoUnp(ByVal upper As Byte, ByVal rower As Byte, oarray() As Byte) Dim cnstr As String Dim g0 As Long Dim g1 As Long g1 = 4 cnstr = CStr(upper * 16^2 + rower) g1 = Len(cnstr) For g0 = 4 To 1 Step -1 oarray(g0) = &HF0 If g1 > 0 Then oarray(g0) = oarray(g0) + CInt(Mid(cnstr, g1, 1)) End If g1 = g1 - 1 Next End Sub
cnvBtoUnpのインタフェースを代えました。この方が都合がよさそう smpを実行してみてください。
b(1),b(2)の値を変えて試してみてください 提示した例は バイナリ 1234 の例です。
ichinose
COBOLは詳しく分かりませんが
最近オブジェクト指向になったみたいですね。
私は現在JAVAを勉強してますが・・・
基本的には、フェンダーさんの考え方と同じですよ
ichinoseさんの知恵をお借りしたとしたら
今まで提示してきたコードで
バイナリ型の入出力を考えるとしたら
下記のコードを見直す必要があるんですかね??
Function B2D2(B1() As Byte) As String
Dim ArrySize As Long
Dim dSize As Long
Dim 符号 As Byte
Dim 上位桁 As Long
Dim s上位桁 As String
Dim 下位桁 As Long
Dim s下位桁 As String
Dim tmp As String
ArrySize = UBound(B1) dSize = ArrySize * 2
tmp = "" For i = 1 To ArrySize
ArrySize = ArrySize
上位桁 = Int(B1(i) / 16) s上位桁 = D2H(CInt(上位桁))
下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁))
tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize)
B2D2 = tmp
End Function
(フェンダー)
>Function B2D2(B1() As Byte) As String
このFunction、パック型からアンパック型に変換する関数ですよね?
>バイナリ10進数2byte変換前 0050 >ゾーン10進数時4byte変換後 F0F0F5F0
Byte型の配列に 0050(16進数)これが入力データだとすると、 F0F0F5F0 という文字列を返すのですよね?
でも、私には、D2H というFunctionプロシジャーを提示してくれないので、 再現が出来ないですよね? 想像は付きますよ、そりゃあね、でも、ここは、D2Hのコードを提示してもらわないと 私がテストできないですから・・・。
まっ、それはそれとして・・・・、
>バイナリ型の入出力を考えるとしたら >下記のコードを見直す必要があるんですかね??
ここでこの御発言をされる ということは、 未だに パックデータとバイナリデータとの違いを御理解いただいていない ということでしょうか? そうなると、
>基本的な算出方法はおそらくこうです。 >0050の場合なら10の位の5に16をかけて80となりF0F0F8F0 >0012の場合なら10の位の1に16をかけて16+2でF0F0F1F8という感じかと思われます。
これも違うかもしれないということになり、私が提示したコードも正しくない かもしれない
と言うことになってしまいます。
パックデータ とバイナリデータのデータの意味が違うのですから、 ここから同じアンパックデータを作成する
入力データが違うのですから、コードは違います。
もう一度、整理しましょう
パックデータとバイナリデータ
1234(16進数) 同じ2バイトのデータで同じ値でも、パックデータと認識した場合と バイナリデータと認識した場合とでは、まるで中身の値は違ってきます。
パックデータとして認識した場合、
1234(16進数) この値は、見てのとおり、10進数の 1234 と解釈します。
16進で表現しても10以上の数字つまり、A〜Fは、出てきません。 出てくるとしたら、形式によってですが、最後のゾーン部分だけです。
バイナリデータと認識した場合は、
1234 1*16^3+2*16^2+3*16^1+4 この計算式で表される数字、つまり、4660が値です。
内部形式では、同じ16進数の1234でも型の認識の違いで 値が違うのですから、変換方法が違うのは 当然ですよね!!
因みにB2D2同様に バイナリデータを変換して文字列で返すなら、
Sub smp() Dim bb(1 To 2) Dim g0 As Long Dim ans As String bb(1) = &H12 bb(2) = &H34 ans = cnvBtoUnp(bb(1), bb(2)) MsgBox ans End Sub Function cnvBtoUnp(ByVal upper As Byte, ByVal rower As Byte) As String Dim ans As String Dim cnstr As String Dim g0 As Long Dim g1 As Long g1 = 4 cnstr = CStr(upper * 16 ^ 2 + rower) g1 = Len(cnstr) For g0 = 4 To 1 Step -1
If g1 > 0 Then ans = "F" & Mid(cnstr, g1, 1) & ans Else ans = "F0" & ans End If g1 = g1 - 1 Next cnvBtoUnp = ans End Function
同じ2バイトで同じ値(16進数)であってもパックデータと見なすか バイナリデータと見なすかで データの意味が違うことを理解してください。
ichinose
もしかして・・・・。
パック型とバイナリ型の違いなど分かっているが、 なんとか、Function B2D2(B1() As Byte) As String
この関数を利用できないか?
ということでしょうか?
だとしたら、
バイナリデータをパック型に変換して、これをB2D2の入力データにすればよいということになりますが。
検討してみてください
ichinose
いや、下記のバイナリ領域の入出力で
Get #InFN, InPOS, バイナリ型
tmpStr = B2D2(バイナリ型)
ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4
Function B2D2(B1() As Byte) As Stringから
利用はしてます。
ichinoseさんの提示していただいたコードで
bb(1) = &H12
bb(2) = &H34
の部分の数値を変更すれば
確かに私が求めていた正確な数値が返ってきます。
因みにDH2のコードはこれですが・・・
Function D2H(itmp As Long) As String
Select Case itmp Case 10 D2H = "A" Case 11 D2H = "B" Case 12 D2H = "C" Case 13 D2H = "D" Case 14 D2H = "E" Case 15 D2H = "F" Case Else D2H = CStr(itmp) End Select
End Function
もう一度整理してみます。
(フェンダー)
B2D2というFunctionプロシジャーやっと、コードの提示があったので、 試してみました。
でも・・・、この関数、想像と違い、
Sub testtest() Dim bb(1 To 2) As Byte bb(1) = &H12 bb(2) = &H34 MsgBox B2D2(bb()) End Sub
こんなテストプログラムで 返されるデータは 1234 という文字列です これは、パック型の内部データをそのまま文字列にしただけですよね?
これを chg_str2byteという関数の入力データにしていますが、 このchg_str2byteでは、何をしているのですか? このコードを提示していただかないと最終的な出力データは見えませんよね?
見せてください
ichinose
いや私が試したのはichinoseさんのコードだけで
bb(1) = &H00
bb(2) = &H05
だったり数値を変更し
結果を確認しただけです。
私の提示したものとは一切継承させてません。
Function B2D2(B1() As Byte) As String
Dim ArrySize As Long
Dim dSize As Long
Dim 符号 As Byte
Dim 上位桁 As Long
Dim s上位桁 As String
Dim 下位桁 As Long
Dim s下位桁 As String
Dim tmp As String
ArrySize = UBound(B1) dSize = ArrySize * 2
tmp = "" For i = 1 To ArrySize
ArrySize = ArrySize
上位桁 = Int(B1(i) / 16) s上位桁 = D2H(CInt(上位桁))
下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁))
tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize)
B2D2 = tmp
End Function
の中で
P型 dSize = ArrySize * 2 -1
B型 dSize = ArrySize * 2
と変えているだけです。
提示希望コードは下記のコードになります。
Function chg_str2byte(uniStr As String, tmpByte() As Byte) As Long
Dim iSize As Long
iSize = Len(uniStr)
chg_str2byte = 1
i = 0 Do While (i < iSize) Select Case Mid(uniStr, i + 1, 1) Case "0" tmpByte(i + 1) = 240 Case "1" tmpByte(i + 1) = 241 Case "2" tmpByte(i + 1) = 242 Case "3" tmpByte(i + 1) = 243 Case "4" tmpByte(i + 1) = 244 Case "5" tmpByte(i + 1) = 245 Case "6" tmpByte(i + 1) = 246 Case "7" tmpByte(i + 1) = 247 Case "8" tmpByte(i + 1) = 248 Case "9" tmpByte(i + 1) = 249 End Select i = i + 1 Loop
End Function
(フェンダー)
>いや私が試したのはichinoseさんのコードだけで >私の提示したものとは一切継承させてません。
これは、わかっています。
ただ、これでフェンダーさんが提示された パック形式データ----->アンパック形式データへ変換 というプログラムが私のほうで再現できました。
>P型 dSize = ArrySize * 2 -1 >B型 dSize = ArrySize * 2
パック型用のコードは、
>P型 dSize = ArrySize * 2 -1
このコードのままなのですね?
これで正常に作動しているのなら、やはり、最後の4Bitは、符号又は、ゾーンなのですね!!
見せていただいた chg_str2byteこれを使えば、2バイトバイナリデータ----->4バイトアンパックデータ の変換は、
Sub test2() Dim bb(1 To 2) As Byte Dim rstr As String Dim rbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H12 bb(2) = &H34 rstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") ReDim rbyte(1 To Len(rstr)) Call chg_str2byte(rstr, rbyte()) ans = "" For g0 = 1 To UBound(rbyte()) ans = ans & Hex(rbyte(g0)) Next MsgBox ans End Sub
Function chg_str2byte(uniStr As String, tmpByte() As Byte) As Long
Dim iSize As Long Dim i As Long iSize = Len(uniStr)
chg_str2byte = 1
i = 0 Do While (i < iSize) Select Case Mid(uniStr, i + 1, 1) Case "0" tmpByte(i + 1) = 240 Case "1" tmpByte(i + 1) = 241 Case "2" tmpByte(i + 1) = 242 Case "3" tmpByte(i + 1) = 243 Case "4" tmpByte(i + 1) = 244 Case "5" tmpByte(i + 1) = 245 Case "6" tmpByte(i + 1) = 246 Case "7" tmpByte(i + 1) = 247 Case "8" tmpByte(i + 1) = 248 Case "9" tmpByte(i + 1) = 249 End Select i = i + 1 Loop
End Function
これでも作動します。
ichinose
P型 dSize = ArrySize * 2 -1
>このコードのままなのですね?
そうです。このままです。
PとBで切り替えてます。
>これでも作動します。
ichinoseさんのコードを加えて
バイナリ入出力はできるのですが
ボックスに値が表示されるだけで
入出力後の値は変わりませんね。
もう少し検証してみます。
(フェンダー)
表示されるだけと言いますが、そのボックスの値は1234(16進数)を 「バイナリ領域をゾーン領域に数値変換した部分を テキストにした数値」になっていませんか。 上でのフェンダーさんの表現にしました。 (cai)
(フェンダー)
>ボックスに値が表示されるだけで >入出力後の値は変わりませんね。
どういうことですか? 具体例を出して、説明してください。
それから
>PとBで切り替えてます。
Bの場合は、B2D2このFunctionは、必要ないですよね、これまでの話の流れでは・・・。
ichinose
FOFOFOFO
と表示されて入出力したデータは変わらないのです。
テストデータの中身にP型とB型が混在しているので
Pの場合→Function P2D2(B1() As Byte) As String
dSize = ArrySize * 2-1
Bの場合→Function B2D2(B1() As Byte) As String
dSize = ArrySize * 2
としています。
(フェンダー)
B2D2を指定しないとReDim tmpByte(1 To Len(tmpStr))が
有効範囲にありませんとなります。
>FOFOFOFO >と表示されて入出力したデータは変わらないのです。 入力データも
FOFOFOFO ということですか?
でも、これは、パック型データではありませんよ!!
又、入力データにFOFOFOFO で パックデータ---->アンパックデータを実行しても 結果は FOFOFOFO とはなりません
意味が違うなら、コードや入力データをきちんと提示してください。 フィードバックは、多少面倒でも繰り返し同じ事を表示していただけないと はっきり意図が伝わりません。隣にいるわけではないのですから・・・・。
ichinose
Sub test1() Dim bb(1 To 4) As Byte Dim tmpstr As String Dim tmpbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &HF0 bb(2) = &HF0 bb(3) = &HF0 bb(4) = &HF0 tmpstr = B2D2(bb())
ReDim tmpbyte(1 To Len(tmpstr)) Call chg_str2byte(tmpstr, tmpbyte()) ans = "" For g0 = 1 To UBound(tmpbyte()) ans = ans & Hex(tmpbyte(g0)) Next MsgBox ans End Sub Function B2D2(B1() As Byte) As String Dim ArrySize As Long Dim dSize As Long Dim 符号 As Byte Dim 上位桁 As Long Dim s上位桁 As String Dim 下位桁 As Long Dim s下位桁 As String Dim tmp As String ArrySize = UBound(B1) dSize = ArrySize * 2 - 1 tmp = "" For i = 1 To ArrySize ArrySize = ArrySize
上位桁 = Int(B1(i) / 16) s上位桁 = D2H(CInt(上位桁))
下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁))
tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize)
B2D2 = tmp
End Function Function chg_str2byte(uniStr As String, tmpbyte() As Byte) As Long
Dim iSize As Long Dim i As Long iSize = Len(uniStr)
chg_str2byte = 1
i = 0 Do While (i < iSize) Select Case Mid(uniStr, i + 1, 1) Case "0" tmpbyte(i + 1) = 240 Case "1" tmpbyte(i + 1) = 241 Case "2" tmpbyte(i + 1) = 242 Case "3" tmpbyte(i + 1) = 243 Case "4" tmpbyte(i + 1) = 244 Case "5" tmpbyte(i + 1) = 245 Case "6" tmpbyte(i + 1) = 246 Case "7" tmpbyte(i + 1) = 247 Case "8" tmpbyte(i + 1) = 248 Case "9" tmpbyte(i + 1) = 249 End Select i = i + 1 Loop
End Function Function D2H(itmp As Long) As String
Select Case itmp Case 10 D2H = "A" Case 11 D2H = "B" Case 12 D2H = "C" Case 13 D2H = "D" Case 14 D2H = "E" Case 15 D2H = "F" Case Else D2H = CStr(itmp) End Select
End Function
test1は、F0F0F0F0 を入力データにしています。
結果は、御自分で確認してください
ichinose
test1は、F0F0F0F0 を入力データにしています。
結果は0F00F00F00となります。
ichinosesさんのコードを加えていないのがこんな感じです。
現在検証中です。
(フェンダー)
>結果は0F00F00F00となります。 そうですねえ、↑こうなりますねえ つまり、 >FOFOFOFO >と表示されて入出力したデータは変わらないのです。
という現象が再現できません。これを説明して頂かないと・・・・、 また、前回も記述しましたが、 >FOFOFOFO は、パック型データでも 2バイトのバイナリデータでもないですよね? 違う形式のデータを 入力データとして、パック型(あるいは、2バイトのバイナリ)を前提にしている プログラムで処理しようとしても動かないのは、当然ですよね!!
このことから、正しく入力ファイルのデータ形式を認識しているのか?
ということが疑われます
それから、 >Sub Main() ここからプログラムの提示はして頂きましたが、これ、私がコピーしただけでは、 作動しませんよね? できれば、今までの投稿を踏まえたコードを見たいのですが・・・。 (もっとも、その時は、データや宣言していない変数の提示も必要ですが)
> Get #InFN, InPOS, 国額 > Cells(iTitle, 5) = "国額" > tmpStr = P2D2(国年加給金額) ここだけちょっと気になりました、これで正しいのですか?
ichinose
Get #InFN, InPOS, 国額
> Cells(iTitle, 5) = "国額" > tmpStr = P2D2(国年加給金額) ここだけちょっと気になりました、これで正しいのですか?
ここは
Get #InFN, InPOS, 国額
Cells(iTitle, 5) = "国額" tmpStr = P2D2(国額) こうなります。
ここからは返事が遅くなります。
(フェンダー)
ん? 分かりません!!
一連の投稿でずっと感じてきたこのかみ合わない感、これは、何かの認識が全く私とフェンダーさんとで 全く違うからだ ということで、その認識の違いが何なのかを探ろうとしてきました。 が、未だに分からないのです。
Mainを以下の様にファイルの読み込み書き出しを削除して
Sub Main()
Dim InFileName As String Dim OutFileName As String
Dim InFN As Long Dim OutFN As Long Dim InFileLen As Long Dim InPOS As Long Dim OutPOS As Long Dim tmpStr As String Dim tmpByte() As Byte
Dim bb(1 To 2) As Byte Dim rstr As String Dim rbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H12 bb(2) = &H34 rstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") ReDim rbyte(1 To Len(rstr)) Call chg_str2byte(rstr, rbyte()) ans = "" For g0 = 1 To UBound(rbyte()) ans = ans & Hex(rbyte(g0)) Next MsgBox ans End Sub
これで実行すると、入力データである1234(16進数)が、 F4F6F6F0 変換されますから、
>データは変わりません。 ではなく、データは変わっています。
何を持って、何と何を比べて >データは変わりません。 と仰っているのか分かりません。
まさか
削除したファイルの読み込みデータと書き出しデータが
Dim bb(1 To 2) As Byte Dim rstr As String Dim rbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H12 bb(2) = &H34 rstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") ReDim rbyte(1 To Len(rstr)) Call chg_str2byte(rstr, rbyte()) ans = "" For g0 = 1 To UBound(rbyte()) ans = ans & Hex(rbyte(g0)) Next MsgBox ans
このコードを追加しても変わらない という意味ではないですよね!! そりゃあ、変わりませんよ!!
上記の例で 2バイトのバイナリデータが 4バイトのアンパックデータに変換できる例をしましました。
このロジックを
InFileName = Cells(1, 2) OutFileName = Cells(2, 2) InFN = FreeFile Open InFileName For Binary As #InFN OutFN = FreeFile Open OutFileName For Binary As #OutFN
InPOS = 1 OutPOS = 1 InFileLen = LOF(InFN) iTitle = 6 'チェック用 エクセルシートのタイトルの行位置 ipos = 7 'チェック用 エクセルシートのデータの行位置・開始 Do While (InPOS < InFileLen)
Get #InFN, InPOS, 漢字桁数 Cells(iTitle, 2) = "漢字桁数" tmpStr = B2D2(漢字桁数) Cells(ipos, 2) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4
ipos = ipos + 1 Loop
Close #InFN Close #OutFN
このコード内に応用しなければ、 >2バイトのバイナリデータが 4バイトのアンパックデータに変換 されませんよ!! で、それは、ご自分で考えてください というのが私の現時点での投稿方法なんです。 丸ごとコードの提示は、ぎりぎりのところで避けたいのです。
2バイトのバイナリデータが 4バイトのアンパックデータに変換 の意味を考えながら検討してみてください。
もし、
>データは変わりません。 の意味が別にあるならば、詳しく説明してください。
ichinose
フェンダー
>検証結果をご報告する予定だったのです。 なるほど・・・、 私は、
>ichinoseさんのコードを加えて >バイナリ入出力はできるのですが >ボックスに値が表示されるだけで >入出力後の値は変わりませんね。 >もう少し検証してみます。
この 入出力後の値は変わりませんね。 の意味が分からなかったから 質問したのです。でも、この理由は、何となくわかりました。
私にとっては、この御質問、 2バイトのバイナリデータ-------->4バイトのアンパック型に変換 という処理が 1234(16進数)---------------->F4F6F6F0 が正しいのなら、
私の回答投稿は、ある程度終わっています。
では、御自身が仰ったように これをフェンダーさんが検証された結果を お待ちしています。
ichinose
>最終的なバイナリからゾーン変換の知識を >理解して書き出せるロジックを作るのが目的
そのとおりです。特にこの 理解して が大事だと思っています。
>すぐ作れて良い知らせが出来るかってとこです。
よい知らせとは、なんでしょうか?
「提示されたコードが理解でき、読み込み/書き込みを完成することが出来ました」
という報告は、確かに よい知らせでしょうねえ!!
でも、 「まだ理解できません、具体例を出して自分の理解できないところを説明します」 から、始まって、御自分が分からないところを記述していただくこと、 自分が理解できないところを御自分の意見をいれながら、ポイントを絞って記述していただく事
これもよい報告なのですよ!!この記述が出来れば、理解するに一歩前進なのですから。
いまところ、それが見えない というかその記述がないのです。
前投稿で・・・、
>パック型10進数からゾーン10進数のプログラムは100%合ってます。 >なぜならテストに合格しているからです。
と言う投稿がありました。
又、その処理過程を担う大事な二つのFunmctionも最後に御提示いただきました。 P2D2、chg_str2byte
理解の早道のために
2バイトバイナリデータ------------>4バイトアンパックデータの変換に
最終結果をだす処理に 敢えて、chg_str2byteを使いました。
bb(1) = &H12 bb(2) = &H34 rstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") ReDim rbyte(1 To Len(rstr)) Call chg_str2byte(rstr, rbyte())
パックデータからアンパックデータの変換は、本来のコードに既に組み込まれていて、 正常に作動しているのですよね?
又、P2D2、chg_str2byte のコードは、御自分で作成したコードですか?
御自分で作成していなくても、理解されていますか?
理解されていれば、実コード(ファイルから読み込んで アンッパク変換し、別ファイル書き込む)に 組み込むことは、調べていただければ、それほど難しいことではないと思っています。
私が懸念していたのは、
バイナリ------アンパックデータの変換のロジックです。 これは、VBAのような高級言語からプログラミングを始めると、分かりにくいのです。 なぜなら、VBAは、プログラムが型変換を自動で知らず知らずに行ってしまうからです。 又、高級言語では、データの内部形式等知らないでもプログラミングはかなりの程度 可能ですから・・。
が、今回の問題は、少しですが、こういう知識が必要です。
理解するのが大変なのは分かっているつもりです。
が、分からない箇所の本質がこのスレッドでは見えませんでした。
これも、ファイルに書き込む直前までのコードを提示した理由の一つです。
わからないのなら、自分が分からない箇所を明確(例を出して)に記述することです。
この記述をしていただければ、
私がわかっていることならば、フェンダーさんに理解していただくまで 説明する努力を今度は、私がしますよ!!
時間はかかってもよいです。
検証された結果を待っています。
ichinose
私がわかっていることならば、フェンダーさんに理解していただくまで
説明する努力を今度は、私がしますよ!!
ご丁寧にどうもありがとうございます。
>私の回答投稿は、ある程度終わっています。
>では、御自身が仰ったように これをフェンダーさんが検証された結果を >お待ちしています。
と前スレで一段落ついていると思います。 また話が長くなってしまいますので とりあえず前スレで 忠告していただいたことは ありがたく受けとめておきます。 それと過去のコードの一部を 削除させていただきますのでよろしくお願いいたします。 どうもありがとうございました。
(フェンダー)
>と前スレで一段落ついていると思います。
私の説明など要らないなら、それはそれでもかまいませんが、
検証された結果は、見せてください。
ichinose
>で、それは、ご自分で考えてください というのが私の現時点での投稿方法なんです。 丸ごとコードの提示は、ぎりぎりのところで避けたいのです。
>私の説明など要らないなら、それはそれでもかまいませんが、
えっとですね。
まだ面倒見て頂くとしたら、何を質問したらよいのですか?
今後はコード内部の話になってきてしまうんですよね。
本来バイナリ進数からアンパック進数を理解して
結果が書きだせるコードを目的として投稿いたしました。
今回結果としてほしいのは
1234というバイナリ進数のデータをアンパック進数になる
計算方法は
1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 4 =4660(F4F6F6F0)
という事が分かりました。
そしてこのコードで結果が得られるという
サンプルコードも作成して頂きました。
Sub smp()
Dim bb(1 To 2) Dim unp(1 To 4) As Byte Dim g0 As Long Dim ans As String bb(1) = &H12 bb(2) = &H34 Call cnvBtoUnp(bb(1), bb(2), unp()) For g0 = 1 To 4 ans = ans & Hex(unp(g0)) Next MsgBox ans End Sub Sub cnvBtoUnp(ByVal upper As Byte, ByVal rower As Byte, oarray() As Byte) Dim cnstr As String Dim g0 As Long Dim g1 As Long g1 = 4 cnstr = CStr(upper * 16^2 + rower) g1 = Len(cnstr) For g0 = 4 To 1 Step -1 oarray(g0) = &HF0 If g1 > 0 Then oarray(g0) = oarray(g0) + CInt(Mid(cnstr, g1, 1)) End If g1 = g1 - 1 Next End Sub
あとはこの計算方法を今のコードに加える開発作業になってきます。
ichinoseさんでしたら
VBAの知識が豊富であると考えますから
そうむずかしいことではないと
考えるかと思います。
私の場合、サンプルのコードを引っ張ってきたり
参考書を読みながらゆっくり
考えて、つまずいた部分は社内のプログラマーに仕上げてもらったりしました。
(現状今、聞けないので投稿したのですが・・・)
ですのでバイナリ進数からアンパック進数の概念が理解できたとしても
それをさっとコードに書き足すのはすぐには出来ないので時間が
かかるので検証しますとお伝えして
投稿を打ち切ったのですが・・・
現在JAVAとVBAを並行して利用してまして。
折角VBAのコードがあるという事で
投稿させて頂いたのです。
(フェンダー)
すぐに結果を出せということはありませんので、 しっかり理解して、コードに書き足す時間が出来た時に、 その結果を教えて頂ければ結構です。 (cai)
Function B2D2(B1() As Byte) As String
Dim ArrySize As Long
Dim dSize As Long
Dim 符号 As Byte
Dim 上位桁 As Long
Dim s上位桁 As String
Dim
tmpByte(i + 1) = 241 Case 下位桁 As Long Dim s下位桁 As String Dim tmp As String
ArrySize = UBound(B1) dSize = ArrySize * 2
tmp = "" For i = 1 To ArrySize ' For Each i In B1 ArrySize = ArrySize
上位桁 = Int(B1(i) / 16 ) s上位桁 = D2H(CInt(上位桁))
下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁))
tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize) If (debug_mode = 1) Then Debug.Print "*" & tmp & "*"
B2D2 = tmp
End Function
のコードを変更(もしくは数値の追加)すれば、求めたい値が書きだせると思っているのですが。
(フェンダー)
私のこの投稿の前二つの記述を拝見しました。最初の頃に比べると、 だいぶ分かりやすい記述になっていますね。 さて、本題です。 Function B2D2(B1() As Byte) As String ↑このプログラムを何度も投稿していましすね。 このインタフェースでプログラムをバイナリ変換用に 作成してあげれば、便利なんでしょうね これは、ちょっと前の投稿から理由がわかりました。
Function B2D2(B1() As Byte) As String
このインターフェースで作れば、
InFileName = Cells(1, 2) OutFileName = Cells(2, 2) InFN = FreeFile Open InFileName For Binary As #InFN OutFN = FreeFile Open OutFileName For Binary As #OutFN InPOS = 1 OutPOS = 1 InFileLen = LOF(InFN) iTitle = 6 'チェック用 エクセルシートのタイトルの行位置 ipos = 7 'チェック用 エクセルシートのデータの行位置・開始 Do While (InPOS < InFileLen) Get #InFN, InPOS, 漢字桁数 Cells(iTitle, 2) = "漢字桁数" tmpStr = B2D2(漢字桁数) Cells(ipos, 2) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4 ipos = ipos + 1 Loop Close #InFN Close #OutFN
このコードが変更なしで使えますからねえ。 実は、このインターフェースにすれば、中身は、 1行で済んでしまいます。 でも私は、それはしたくなかったんです。
それをすれば、フェンダーさんも仰った
>最終的なバイナリからゾーン変換の知識を >理解して書き出せるロジックを作る の理解が達成できずに終わってしまいそうだったからです。
で、 バイナリデータ------> アンパックデータ変換 のコードを複数記述しましたが、 以下のコードを使うことで検討してください。たぶん、一番わかりやすいと判断しました、
Sub test1() Dim bb(1 To 2) As Byte Dim tmpstr As String Dim tmpbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H12 bb(2) = &H3F tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") ReDim tmpbyte(1 To Len(tmpstr)) Call chg_str2byte(tmpstr, tmpbyte()) ans = "" For g0 = 1 To UBound(tmpbyte()) ans = ans & Hex(tmpbyte(g0)) Next MsgBox ans End Sub ‘対比していただくコードとして、パック------アンパック変換をtest2とします。 Sub test2() Dim bb(1 To 2) As Byte Dim tmpstr As String Dim tmpbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H12 bb(2) = &H3F tmpstr = P2D2(bb())
ReDim tmpbyte(1 To Len(tmpstr)) Call chg_str2byte(tmpstr, tmpbyte()) ans = "" For g0 = 1 To UBound(tmpbyte()) ans = ans & Hex(tmpbyte(g0)) Next MsgBox ans End Sub
‘以下test1,test2の実行に必要なプロシジャー
Function P2D2(B1() As Byte) As String Dim ArrySize As Long Dim dSize As Long Dim 符号 As Byte Dim 上位桁 As Long Dim s上位桁 As String Dim 下位桁 As Long Dim s下位桁 As String Dim tmp As String ArrySize = UBound(B1) dSize = ArrySize * 2 - 1 tmp = "" For i = 1 To ArrySize ArrySize = ArrySize 上位桁 = Int(B1(i) / 16) s上位桁 = D2H(CInt(上位桁)) 下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁)) tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize) P2D2 = tmp End Function Function chg_str2byte(uniStr As String, tmpbyte() As Byte) As Long Dim iSize As Long Dim i As Long iSize = Len(uniStr) chg_str2byte = 1 i = 0 Do While (i < iSize) Select Case Mid(uniStr, i + 1, 1) Case "0" tmpbyte(i + 1) = 240 Case "1" tmpbyte(i + 1) = 241 Case "2" tmpbyte(i + 1) = 242 Case "3" tmpbyte(i + 1) = 243 Case "4" tmpbyte(i + 1) = 244 Case "5" tmpbyte(i + 1) = 245 Case "6" tmpbyte(i + 1) = 246 Case "7" tmpbyte(i + 1) = 247 Case "8" tmpbyte(i + 1) = 248 Case "9" tmpbyte(i + 1) = 249 End Select i = i + 1 Loop End Function Function D2H(itmp As Long) As String Select Case itmp Case 10 D2H = "A" Case 11 D2H = "B" Case 12 D2H = "C" Case 13 D2H = "D" Case 14 D2H = "E" Case 15 D2H = "F" Case Else D2H = CStr(itmp) End Select End Function
test1 と test2を本当によく見比べてください。
共通部分もあります。 どこが共通なのか?そして、どこが違うのか?
Function chg_str2byte(uniStr As String, tmpbyte() As Byte) As Long
test1 と test2の 両方に使われているこのchg_str2byteというプロシジャー 何をするプロシジャーなのか? このプロシジャーへの入力データである uniStrは、どんなデータなのか 又、出力データであるtmpbyte()は、どんなデータなのか?
これを理解することです。
>1234というバイナリ進数のデータをアンパック進数になる >計算方法は
>1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 4 =4660(F4F6F6F0) >という事が分かりました。 今回の例ではパック型の対比もあるので バイナリデータを 123f にしましたが、考え方は同じで
1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 15(F)=4671 となりますが、test1では、どこでこの計算をしていると思いますか?
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") この1行でそれをしています。結果は、文字列でだしています。
試しに
Sub test3() Dim bb(1 To 2) As Byte Dim tmpstr As String Dim tmpbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H12 bb(2) = &H3F tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000") MsgBox tmpstr End Sub
これを実行して、tmpstrの値を表示して考えてください。
このことを踏まえて、再度 test1 とtest2を見比べてください。
そして、パックデータを読み込み、これをアンパックデータに変換しファイルに書き込む コードを見てください。消されてますが、 P2D2を使い、Get Putとしている箇所です。
test1 とtest2は、見た目は 似ています。
変換されたデータをどのように書き込み(Put)すればよいのか?
見えてきませんか?
よくよく、test1とtest2を良く見比べてください。
ichinose
実はバイナリ進数とアンパック進数の事を
理解したかったのと加えて
現在のコードに対して
どう考えないといけないのか
ほんとはこの部分を勉強したかったんですよね。
コードのアルゴリズムが長けているのであれば
プログラムの土台はすでに出来上がっているし
あとはバイナリとアンパックの関係を
理解すれば投稿しなくて済むものと思います。
高級言語でいう、人間の感覚・視点からチェックしたら
test1 test2の違いは
tmpstr の部分になりますよね??
ですからtest1のtmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")
の部分がP2D2の部分に精通しているわけで
そう考えると
P2D2にある
For i = 1 To ArrySize
ArrySize = ArrySize 上位桁 = Int(B1(i) / 16) s上位桁 = D2H(CInt(上位桁)) 下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁)) tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i の計算式をまず考えなければいけないという事でよろしいでしょうか?? ただ私はVBAの構文は慣れていないので Format(bb(1) * 16 ^ 2 + bb(2), "0000")と同じように(移植)するには どうすればよいのかという事になってきます。
例えばこういう場合mod関数じゃなくで違う構文に書き換えないと
だめですよってなるとすぐにはできない部分ではあります。
それとこのchg_str2byteのプロシージャにあるtmpbyte
これはVB(VBA)でしか通用しないロジックになりますよね?
私の記憶が確かなら社内のプログラマが言っており
これはほかの言語では通用しないと。
この部分が一番分かりにくい部分ではあります。
実際このあたりも少し再構築しなければいけないのかもしれないのですし
またuniStrの関数も
アスキー文字列を各国語文字列に変換するぐらいのことしかわかってません。
P2D2の上位桁 = Int(B1(i) / 16)の部分に関しては
上位桁 = Int(B1(i) / 16 * 16)の変更でいいんじゃないでしょうか??
(フェンダー)
>tmpstr の部分になりますよね?? そうですね、ここですよね
どこかは、違わなければ、
test1は、バイナリ---->アンパック
test2は、パック------>アンパック
の変換とプログラムの入力データの型が違いますから、結果が変わってきません。
>の計算式をまず考えなければいけないという事でよろしいでしょうか?? P2D2内で行われている計算の意味が分からないなら、理解はしてください。
>Format(bb(1) * 16 ^ 2 + bb(2), "0000")と同じように(移植)するには >どうすればよいのかという事になってきます。
P2D2というプロシジャーは、完成されているのですよね? ですから、1行で書けるようにしてください ということではありませんよ!!
test1とtest2の処理の違いは、
P2D2で行われている処理と Format(bb(1) * 16 ^ 2 + bb(2), "0000") この計算の違いです、これが結果を変えているのです。 この処理の違いがパックデータとバイナリの違いです。
そして、この処理の出力データであるtmpstrという文字列型変数には、何が返されるのか? です。
ここでちょっと、chg_str2byteの話に移りましょう
>これはVB(VBA)でしか通用しないロジックになりますよね? これは、何を持って このように仰ったのでしょうかねえ?
>アスキー文字列を各国語文字列に変換する アスキー文字列と言ってもここに入ってくるのは、アスキーの数字文字列だけですが、 これをEBCDICコードの数字文字列に変換し、それぞれの数字を1バイト変数に入れています。
文字列が "123"なら、F1F2F3という内部コードになるように変換しているのです。 このF1F2F3は、EBCDICコードを使っているコンピュータでは、123と表示されます。
ここでは、アンパックデータ=EBCDICコードの数字文字列と見なしているのだと思います。
よって、chg_str2byteは、 アスキーの数字文字列をEBCDICコードの数字文字列コードに変換し、変換したコードをバイト型変数の配列として出力しています。
このバイト型配列を ファイルに書き込んでいますよね(例のPUTです)
元に戻りましょう。
先ほどの >この処理の出力データであるtmpstrという文字列型変数には、何が返されるのか?
このtmpstrがchg_str2byteというプロシジャーの入力データになっているのですから、 これは、アスキーの数字文字列ということになります。
VBAでは、普通に数字文字列です。
よって、
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")
は、2バイトバイナリデータを数字文字列に変換し、
P2D2は、パックデータを数字文字列に変換していることになります。
尚、
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")
このステートメントの
Format(数字データ,"0000")
ですが、数字データが必ず、4文字になるようにしています。
数字データが1234なら 1234 数字データが14なら 0014 数字データが1なら 0001
という文字列を返します。そうしないと4バイトのアンパックデータにならないので・・・。
ここまでの記述で 不明な点があれば、投稿して下さい。
ichinose
>アスキーの数字文字列をEBCDICコードの数字文字列コードに変換し、変換したコードをバイト型変数 >の配列として出力しています。
説明どうもありがとうございました。
一応再確認という事で勉強になります。
>これは、何を持って このように仰ったのでしょうかねえ?
256byteでの数式の配列を作成するコードは
他の言語では通用しないすなわちVBAでしか通用しないだったかなーと。
ですが、このような発言をされるという事は
おそらく私が間違って認識していただけかもしれません。
まずは
1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 4 =4660(F4F6F6F0)と
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")が同等のものと認識出来ないので
P2D2に置き換えて理解しようとすることが出来ないのだと思います。
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")は
解読すると
Format(文字列に変換)でP2D2でいう上位桁*16の2剰+下位桁に
になりますよね?
P2D2では移植しようとは思ってませんでしたけど
上位桁と下位桁を別々で計算して
最終的にtmp+上位桁+下位桁となってますが
下記のコードでテストすると
dSize = ArrySize * 2 - 1を
桁を削らないように
dSize = ArrySize * 2とします。
で、上位桁 = Int(B1(i) / 16)を
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")を考えて
上位桁 = Int(B1(i) / 16 * 16)すると
0050はF0F0F8F0と取得したかった文字列が返ってきました。
ですが他の数値になると
異なる数値が返ってきます。
冒頭で話した通り
1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 4 =4660(F4F6F6F0)が
この計算式
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")でなぜ結果が返ってくるのか?
精通してることが認識出来ない限り
作業は現状困難だと思ってます。
よって理解しようしても出来ないのが正直な回答です。
Sub test2() Dim bb(1 To 2) As Byte Dim tmpstr As String Dim tmpbyte() As Byte Dim ans As String Dim g0 As Long bb(1) = &H00 bb(2) = &H50 tmpstr = P2D2(bb()) ReDim tmpbyte(1 To Len(tmpstr)) Call chg_str2byte(tmpstr, tmpbyte()) ans = "" For g0 = 1 To UBound(tmpbyte()) ans = ans & Hex(tmpbyte(g0)) Next MsgBox ans End Sub
Function P2D2(B1() As Byte) As String Dim ArrySize As Long Dim dSize As Long Dim 符号 As Byte Dim 上位桁 As Long Dim s上位桁 As String Dim 下位桁 As Long Dim s下位桁 As String Dim tmp As String ArrySize = UBound(B1) dSize = ArrySize * 2 For i = 1 To ArrySize ArrySize = ArrySize 上位桁 = Int(B1(i) / 16 * 16) s上位桁 = D2H(CInt(上位桁)) 下位桁 = B1(i) Mod 16 s下位桁 = D2H(CInt(下位桁)) tmp = tmp & CStr(s上位桁) & CStr(s下位桁) Next i tmp = Mid(tmp, 1, dSize) P2D2 = tmp End Function Function chg_str2byte(uniStr As String, tmpbyte() As Byte) As Long Dim iSize As Long Dim i As Long iSize = Len(uniStr) chg_str2byte = 1 i = 0 Do While (i < iSize) Select Case Mid(uniStr, i + 1, 1) Case "0" tmpbyte(i + 1) = 240 Case "1" tmpbyte(i + 1) = 241 Case "2" tmpbyte(i + 1) = 242 Case "3" tmpbyte(i + 1) = 243 Case "4" tmpbyte(i + 1) = 244 Case "5" tmpbyte(i + 1) = 245 Case "6" tmpbyte(i + 1) = 246 Case "7" tmpbyte(i + 1) = 247 Case "8" tmpbyte(i + 1) = 248 Case "9" tmpbyte(i + 1) = 249 End Select i = i + 1 Loop End Function Function D2H(itmp As Long) As String Select Case itmp Case 10 D2H = "A" Case 11 D2H = "B" Case 12 D2H = "C" Case 13 D2H = "D" Case 14 D2H = "E" Case 15 D2H = "F" Case Else D2H = CStr(itmp) End Select End Function
(フェンダー)
>1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 4 =4660(F4F6F6F0)と >tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")が同等のものと認識出来ないので >P2D2に置き換えて理解しようとすることが出来ないのだと思います。
いよいよ、ここですね
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")
この計算の意味です。
例 二桁の数字 12 と二桁数字 34 共に10進数です。 この二つの数字を使って 1234という4桁数字を作る計算式を考えると・・・、
12*10^2+34=1234
ですよね!! 10進数ですから、桁を1桁上げるに10を掛け、桁を2桁上げるなら、10^2(つまり、100を掛ける)
例
2進数の11(10進の3)の桁を上げて 110(10進の6)にするには、 2進数ですから、11に2を掛けると 11が 110 になります。 2進数の11を 1100に桁を上げるには 11に2^2を掛けると 1100になります。
では、 tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")
この計算に戻りましょう。 bb(1)には、 &h12 という二桁の16進数が入っています。 bb(2)には、 &h34 という二桁の16進数が入っています。
二桁の16進数 &h12 と二桁16進数 &h34 。 この二つの数字を使って &h1234という4桁16進数を作る計算式を考えると・・・、 16進数 &h12 の桁を2桁上げるのですから、
&h12*16^2+&h34 =&h1234 となります。 (尚、&hは、16進数であると言う記号です) よって、bb(1) * 16 ^ 2 + bb(2) この計算式が出てくるんです
さて、ここからがVBAの便利なところ
VBAでは、16進で計算しようが、10進で計算しようが、はたまた 16進、10進混在で計算しようが、 答えは、10進で表示されます。
Sub その証拠() Dim bb(1 To 2) As Byte bb(1) = &H12 bb(2) = &H34 MsgBox bb(1) * 16 ^ 2 + bb(2) MsgBox &H12 * 16 ^ 2 + &H34 End Sub
つまり、 1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰 + 4
このような計算をして 16進から10進に変換する計算式を書かなくてもVBAが 勝手にやってくれるのです。ちゃんちゃん!!
既に10進に変換された数字をFormat(・・・)を使って、文字列にするので
4660という文字列の数字が変数tmpstrに格納されます。
これでいかがでしょうか?
個々を理解したうえで尚且つ、B2D2をP2D2の改良で行いたいなら、 これは、これで考えますが、上記が理解されたら、 この方法で ファイル書き込みを行ってください。
ichinose
>個々を理解したうえで尚且つ、B2D2をP2D2の改良で行いたいなら、
これは、これで考えますが、
tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")の計算式が
分かれば見えてくるのかなって思ったのですが
そんな甘くはないようですね。
作成していただいたコードって
毎回4桁の数値を指定する構文ですよね
bb(1) = &H00
bb(2) = &H50
これがよくわからないのですが
P2D2のロジックがあるのにこれを利用しないで
Get #InFN, InPOS, 漢字桁数 Cells(iTitle, 2) = "漢字桁数" tmpStr = B2D2(漢字桁数) Cells(ipos, 2) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4
バイナリ用のコードを作成して書き込むという事ですよね。
うーん。
これをコードにするには・・・・・
何がわからないのって言われると
何を質問すれば伝わるかなって答えになってしまいます。
ichinoseさんはもうほとんど答えを出してくれていると
思うのですが、
ここまで来ると逆に何を質問すればいいのか
コードで考えると分からなくなってきました。
もう少し考えてみます。
(フェンダー)
Get #InFN, InPOS, 漢字桁数
Cells(iTitle, 2) = "漢字桁数" tmpStr = B2D2(漢字桁数) Cells(ipos, 2) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4 の tmpStr = B2D2(漢字桁数)を 呼び出さずに Format(bb(1) * 16 ^ 2 + bb(2), "0000")のような コードを 前スレの計算方法を理解しつつ 1行書き込む。 それなら1行で済んでしまう。
考え方の方向性としては合ってますでしょうか??
(フェンダー)
>考え方の方向性としては合ってますでしょうか? 昼間は、私も仕事なので、長く記述できませんが、
そういうことです。
もう少しです。
ichinose@私の会社には、キッコーマンの醤油さしがない
'************************
Get #InFN, InPOS, 漢字桁数 Cells(iTitle, 2) = "漢字桁数" tmpStr = B2D2(漢字桁数) Cells(ipos, 2) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4 '************************
だったコードを
'************************
Get #InFN, InPOS, 氏名漢字桁数 Cells(iTitle, 2) = "氏名漢字桁数"
tmpStr = (氏名漢字桁数(1) * 16 ^ 2 + 氏名漢字桁数(2)) Cells(ipos, 2) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4 '************************
のように変更し
バイナリファイルを入出力しました。
いまのとこ
1234だったり先頭から0が付かない2バイトのデータは
F4F6F6F0と
正確な数値で書き出せるのですが
先頭から0が付く
2バイトデータは下記のようになります。
例 0005 → F8F0F0F0
で、過去スレで下記のように
>tmpstr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")
このステートメントの
Format(数字データ,"0000")
ですが、数字データが必ず、4文字になるようにしています。
数字データが1234なら 1234 数字データが14なら 0014 数字データが1なら 0001
という文字列を返します。そうしないと4バイトのアンパックデータにならないので・・・。
と教えていただいたので
tmpStr = (氏名漢字桁数(1) * 16 ^ 2 + 氏名漢字桁数(2))の部分に
"0000"を加えようとしているのですが
現状コンパイルエラーとなり検証中です。
Cells(ipos, 2) = tmpStrで、数値をチェックする限り
取得したい文字はすべて一致しました。
あとは数字データが必ず、4文字になるように出来れば
私の判断が間違ってなければ解決するかと思います。
(フェンダー)
'************************
Get #InFN, InPOS, 漢字桁数 Cells(iTitle, 3) = "漢字桁数"
tmpStr = Format(漢字桁数(1) * 16 ^ 2 + 漢字桁数(2), "0000") Cells(ipos, 3) = tmpStr ReDim tmpByte(1 To Len(tmpStr)) j = chg_str2byte(tmpStr, tmpByte) Put #OutFN, OutPOS, tmpByte InPOS = InPOS + 2 OutPOS = OutPOS + 4 '************************
(フェンダー)
この質問内容からの 延長線上の話になりますので、ご質問させていただきます。
例えばDATデータが1レコード829バイトあり 10件のデータ8290バイトのDATデータがあったとします。 1レコードずつの先頭の 4バイトずつを削除していきたいのですが、 やり方が分かりません。 すいませんがここで勉強させてください。 どうぞよろしくお願いします。
例
1レコード目→先頭4バイト削除 2レコード目→先頭4バイト削除 3レコード目→先頭4バイト削除 4レコード目→先頭4バイト削除 5レコード目→先頭4バイト削除 6レコード目→先頭4バイト削除 7レコード目→先頭4バイト削除 8レコード目→先頭4バイト削除 9レコード目→先頭4バイト削除 10レコード目→先頭4バイト削除
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
8290バイト→8250バイト
(フェンダー)
手順としては・・・・、
1 元ファイル(ここでいう1レコード829バイトのファイル)を開く
2 新規ファイル(ここでいう1レコード825バイトのファイル)を開く
3 元ファイルからデータを読み込む(Get)
4 829バイトデータを825バイトデータに編集
5 新規ファイルに編集したデータを書き込む(Put)
6 3〜5を元データがなくなるまで繰り返し
7 元ファイル 新規ファイルを閉じる
8 元ファイルを削除
9 新規ファイル名を 元ファイル名に変更する
という手順です。具体例は、次投稿にて
尚、今回のご質問は、新規投稿を行い、関連があるなら、このスレッドを リンクした方がよかったと思いますよ!!
ichinose
新規ブックの標準モジュールに以下のコードをコピーしてください
'======================================================================= Option Explicit Type b26 b(1 To 26) As Byte End Type Type b4to22 b1(1 To 4) As Byte b2(1 To 22) As Byte End Type Const fl = "Sample.dat" '==================================================== Sub サンプルデータの作成() Dim b As b26 Dim g0 As Long Dim fno As Long For g0 = 1 To 26 b.b(g0) = 64 + g0 Next On Error Resume Next Kill ThisWorkbook.Path & "\" & fl On Error GoTo 0 fno = FreeFile Open ThisWorkbook.Path & "\" & fl For Random As #fno Len = LenB(b) For g0 = 1 To 10 Put #1, , b Next Close #fno End Sub '==================================================================== Sub サンプルデータの表示() Dim b As b26 Dim g0 As Long Dim fno As Long fno = FreeFile Open ThisWorkbook.Path & "\" & fl For Random As #fno Len = LenB(b) Get #fno, , b Do Until EOF(fno) MsgBox "第 " & g0 + 1 & "レコード : " & StrConv(b.b, vbUnicode) g0 = g0 + 1 Get #1, , b Loop Close #fno End Sub '==================================================================== Sub 変換() Dim b As b4to22 Dim g0 As Long Dim fno1 As Long Dim fno2 As Long fno1 = FreeFile Dim a As String Open ThisWorkbook.Path & "\" & fl For Random As #fno1 Len = LenB(b) On Error Resume Next Kill ThisWorkbook.Path & "\" & Replace(fl, ".dat", ".tmp") On Error GoTo 0 fno2 = FreeFile Open ThisWorkbook.Path & "\" & Replace(fl, ".dat", ".tmp") For Random As #fno2 Len = UBound(b.b2) g0 = 0 Get #fno1, , b Do Until EOF(fno1) Put #fno2, , b.b2 Get #fno1, , b Loop Close #fno1 Close #fno2 On Error Resume Next Kill ThisWorkbook.Path & "\" & fl Name ThisWorkbook.Path & "\" & Replace(fl, ".dat", ".tmp") As ThisWorkbook.Path & "\" & fl End Sub '==================================================================== Sub 結果表示() Dim b(1 To 22) As Byte Dim g0 As Long Dim fno As Long fno = FreeFile Open ThisWorkbook.Path & "\" & fl For Random As #fno Len = UBound(b) Get #fno, , b Do Until EOF(fno) MsgBox "第 " & g0 + 1 & "レコード : " & StrConv(b, vbUnicode) g0 = g0 + 1 Get #1, , b Loop Close #fno End Sub
コード説明
まず、上記のコードをコピー後、一度適当な名前でブックを保存してください。
保存後、サンプルデータの作成を実行してください。
この「サンプルデータの作成」は、A〜Zの文字コードを10回書き込んだ簡単なデータです
つまりA〜Z、26バイトのデータを10回書き込んだ260バイトのファイルです。
サンプルデータの内容を「サンプルデータの表示」を実行して確認して下さい。
10レコード分の A〜Z が表示されるはずです。
この260バイトのサンプルファイル(Sample.dat)の26バイトのデータの先頭4バイト分を 削除したファイルを作成するのが、「変換」 というプログラムです。
結果は、A〜Zの内の先頭A〜Dを削除するのですから、E〜Zの22バイトのデータを10回 書き込んだファイルになるはずです。
再構築されたSample.dat 表示は、結果表示 というプログラムを実行して 確認して下さい。E〜Zが10回表示されるはずです。
上記は、1レコード26バイト、260バイトのファイルのレコードの先頭4バイトを 削除して、1レコード22バイト、220バイトのファイルを作成した例です。
上記コードを調べて、理解して、実際のファイルに応用してください。
尚、ファイルに関する I/Oでは、本来はもっと細かいエラーチェックが 必要です。今回は、省略していますが・・・。
ichinose
バイト削除の件、新規投稿させていただきました。 引き続きこちらのレスでご質問ですが 以前バイナリ進数からゾーン進数への 数値表現変換を勉強させていただきました。 前回は 2バイトから4バイトへの変換でしたが 今回は 4バイトから8バイトへの変換でご質問させていただきます。
1234(2バイトデータ)1*16進数3剰 + 2*16進数2剰 + 3*16進数1剰+ 4 VBA計算式→ tmpStr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")で VBAがバイナリ2バイトからゾーン4バイトへ 自動的に計算してくれると教えていただきました。
12345678と4バイトのバイナリ進数データがあったとします。 4バイトから8バイトへの変換計算式でいうと 1*16進数7剰 + 2*16進数6剰 + 3*16進数5剰+4*16進数4剰 +5*16進 数3剰 + 6*16進数2剰++ 7*16進数1剰+8 の計算式になりますよね?? VBAが自動的にしてくれる計算方式がよく分からないのですが・・・ よろしくお願いします。
(フェンダー)
こっちのスレッドにも質問があることを見逃していました。 >tmpStr = Format(bb(1) * 16 ^ 2 + bb(2), "0000")で
1バイトデータ二つをバイナリデータに見立てて10進数に変換する計算は、上記でしたね!!
今度は、 1バイトデータ4つをバイナリデータに見立てて10進数に変換する計算は、
1バイトのデータは、二桁の16進数が入っていると見なせますから、
Dim bb(1 To 4) As Byte Dim tmpstr As String bb(1) = &H12 bb(2) = &H34 bb(3) = &H56 bb(4) = &H78
この四つ配列から、 &h12345678 という8桁の16進データを作るには?
bb(1)のデータは、6桁桁上げするのですから、16^6を掛ける bb(2)のデータは、4桁桁上げするのですから、16^4を掛ける bb(3)のデータは、2桁桁上げするのですから、16^2を掛ける bb(4)のデータは、0桁桁上げするのですから、何も掛けない(正確には,16^0=1を掛ける)
ということになります。
10進数ならば、どうすればよいかをまず考えて、その規則を16進に当てはめていくと理解できます。
よって、今回の例題だと
Sub test2() Dim bb(1 To 4) As Byte Dim tmpstr As String bb(1) = &H12 bb(2) = &H34 bb(3) = &H56 bb(4) = &H78 tmpstr = Format(bb(1) * 16 ^ 6 + bb(2) * 16 ^ 4 + bb(3) * 16 ^ 2 + bb(4), "00000000") MsgBox tmpstr End Sub
表示される値は、305419896 で9桁ですね!! これでは、8桁を越えてしまいます。
これは、前回の2バイトバイナリデータのときも懸念されていたことですが
実際には、&h12345678 このような数字は、4バイトバイナリデータとしては,入ってこないと 思われます。&h5F5E0FF ここまでの数字しかしか入ってこないと思います。
オフコンの言語には、10進の桁数で変数が定義できるものがありますからね!!
以上です これも新規投稿を行い、このスレッドを リンクした方がよいと思いますよ!! このスレ、長いでしょう? ichinose
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.