タイトル : Re^3: COMP-3の変換につて 投稿日 : 2017/09/22(Fri) 19:00 投稿者 : 魔界の仮面弁士
> 元々は汎用機やサーバのCobolerでして、 私は逆に、COBOL の読み書きができないんですよね…。orz .NET Framework 対応の COBOL 言語を数時間触ったことがあって、 COMP-3 形式 とかもその時に概念として齧ったことがある程度で。 > パック形式のシーケンシャルファイルから > SQL-Serverに一括登録するプログラムを作っています。 SQL Server への格納が目的なのであれば、SQL Server 側で dbo.fn_varbintohexstr(@pack) で 16進数化して、符号だけ切り出して decimal 変換するのも手かと思います。 たとえば後述の Transact-SQL を実行すると、下記の変換結果が得られます。 実際に使うときは、VARBINARY(もしくは 16進数文字列な VARCHAR)を受け取って 戻り値として DECIMAL を返すような FUNCTION を SQL Server 側に作成しておくと便利かと。 ID HEX VALUE --- ------------ ------- 例1 0x000489944c 489944 例2 0x000009834c 9834 例3 0x000015048c 15048 例4 0x000007982c 7982 例5 0x000011439c 11439 例6 0x01234d -1234 ----------------------------- DECLARE @pack1 VARBINARY(255); DECLARE @pack2 VARBINARY(255); DECLARE @pack3 VARBINARY(255); DECLARE @pack4 VARBINARY(255); DECLARE @pack5 VARBINARY(255); DECLARE @pack6 VARBINARY(255); SET @pack1 = 0x000489944c; SET @pack2 = 0x000009834c; SET @pack3 = 0x000015048c; SET @pack4 = 0x000007982c; SET @pack5 = 0x000011439c; SET @pack6 = 0x01234d; WITH CTE1 (ID, VALUE) AS ( SELECT '例1', @pack1 UNION ALL SELECT '例2', @pack2 UNION ALL SELECT '例3', @pack3 UNION ALL SELECT '例4', @pack4 UNION ALL SELECT '例5', @pack5 UNION ALL SELECT '例6', @pack6 ), CTE2 (ID, HEX) AS ( SELECT ID, dbo.fn_varbintohexstr(VALUE) FROM CTE1 ), CTE3 (ID, HEX, VALUE) AS ( SELECT ID, HEX, CASE WHEN HEX LIKE '0x%[a-f]_%' THEN NULL WHEN HEX LIKE '0x%c' THEN +1 WHEN HEX LIKE '0x%d' THEN -1 END * CONVERT(DECIMAL, REPLACE(REPLACE(REPLACE(HEX, 'd', ''), 'c', ''), '0x', '')) FROM CTE2 ) SELECT * FROM CTE3 ORDER BY ID > 厚かましいとは思いますが、実験で作られたプログラムの解説をお願い > できないでしょうか。本当に申し訳ありません。 実験コード自体の解説をしても、あまり意味は無いと思いますよ。 今回の問題は、COMP3_CNV_RTN に渡すべき「データ」を どこからどうやって取得しているのかが問題だからです。 渡すべきデータが間違っている(というか破損している)ために生じた問題ですので、 最初に御提示頂いたコードだけを見ても、原因は特定できません。 『パック形式のシーケンシャルファイル』を読み取っているコードを見せてください。 ついでに、変換元ファイルの具体的な内容も分かると説明しやすいです。 >> ループカウンタすらローカル変数になっていないなど、 >> モジュールレベル変数(フィールド変数)を使いすぎな点が気にかかります。 > 元々は汎用機やサーバのCobolerでして、ご指摘のようなことを気にして > おりませんでした。以後は気を付けます。 ほとんどの変数は、ローカル変数として宣言されるべきです。 (ローカル変数とは、Sub〜End Sub / Function〜End Function の中で宣言される Dim のことです) また、処理結果を返却するためには、Function の戻り値を使うのが望ましいです。 たとえば今回のケースなら、COMP3_CNV_RTN の実装は、 Function COMP3_CNV_RTN(ByRef C3() As Byte) As String もしくは Function COMP3_CNV_RTN(ByVal C3 As String) As String などとするのが良いと思います。CNT 引数をつけるかどうかはお好みで。 > ByValに関しては理解できていないためです。 今回の『Sub COMP3_CNV_RTN(C3 As String, CNT As Integer)』の場合、 Sub COMP3_CNV_RTN(ByVal C3 As String, ByVal CNT As Integer) にした方が良いということです。 引数に ByVal も ByRef もつけなかった場合、VB6 では ByRef 扱い、VB.NET では ByVal 扱いになります。 ByVal は「呼び出し元からデータを受け取る」ためのものですが、 ByRef は「呼び出し元にデータを返却する」ための出力引数です。 (ただし VB6 では、配列やユーザー定義型を渡す場合は、ByVal 扱いにできません) 今回の COMP3_CNV_RTN の中では「C3 の内容を読み取る」ことはあっても、 「呼び出し元に返却するために C3 の内容を書き換える」ことはないので、 ByVal をつけるべきである、ということです。 また先の例においては、Command1 のコードにて Dim bin5() As Byte bin5 = HexStringToBinary(src) Call COMP3_CNV_RTN((bin5), 5) と書いておりますが、もしもこれを Dim bin5() As Byte bin5 = HexStringToBinary(src) Call COMP3_CNV_RTN(bin5, 5) にしてしまうと、コンパイルエラー『ByRef 引数の型が一致しません。』が表示されることになります。 Command2 の方についても、変数 MOTO のデータ型が String では無かった場合 (たとえば、Dim MOTO As Variant や Dim MOTO() As Byte だった場合)において 同様にコンパイルエラー『ByRef 引数の型が一致しません。』が表示されます。 しかし引数が、ByVal で宣言されていれば、上記のコンパイルエラーになることなく 動作させることができます。その分、利用する際にも使いやすくなると思いますよ。 |