[三流君] −−>
[プログラマー業務の愚痴] −−>
[バックナンバー一覧]
−−> No.197 テストデータは汚いデータで?(都合の悪いデータで)
テストデータは汚いデータで?(都合の悪いデータで)
本文(発行内容)
テストデータは汚いデータで?(都合の悪いデータで)
こんにちは、
今回も、バグりまくりの自分のプログラム、イヤ取り組み方をネタにしてみます。
はぁ〜、想定外のデータかぁ・・・
/*
* 1.今回のキッカケ
*/
2進数16進文字列変換のバグを通じて、
小手先の修正方法と考え直した方法を書いてみます。
何か、感じる部分があればうれしいです。
実力アップや、なにかのキッカケになればうれしいです。
/*
* 2.現状と問題点
*/
まず、バグが発生したら、現状と問題点を把握します。
下記2進数文字列を16進数文字列に変換するプログラムの場合
'2進文字列を受け取り16進文字列を返す
Function STR2toHEX16(str2 As String) As String
Dim strHEX As String
Dim n As Integer 'ループカウンタ
Dim i As Integer 'ループのカウンタ
Dim n8421 As Integer '8 4 2 1の数値計算用
Dim nBYTE As Integer
strHEX = "" '結果のエリアを初期化する
'文字数分ループする
For n = 1 To Len(str2) Step 4 '4文字(1バイト)単位にループを作る
n8421 = 8 '初期値に8を代入する(上から計算したいので)
nBYTE = 0 '1バイト計算用変数を初期化
For i = 0 To 3 '4回まわるよ(4ビット分)
'ビットが立っているかチェックする
If Mid(str2, n + i, 1) = "1" Then
nBYTE = nBYTE + n8421 'ビットに対応した数値を+する
End If
'次のビットを計算したいので2で割る
n8421 = n8421 / 2
Next i
'計算して、1倍との数値が完成したので16進文字にしてセットする
strHEX = strHEX & Hex(nBYTE)
Next n
'リターン値をセットして関数を抜ける
STR2toHEX16 = strHEX
End Function |
テストでは、それなりに動作してました。
010001 の 2進数文字列を渡すと、44と違う答えが返ってきます。
えっ?と作った本人はびっくりします。
先輩が、
? STR2toHEX16("010001")
とやってみたら、
リターン値が、
44
と返ってきたとクレームを付けて来た。
本来なら、2進数010001は、
01 0001
で、
11となってほしいのに。
作成者は、そんなの桁が足りないんだよと言い出す始末。
※噛み合ってない・・・
まぁ、原因は、4個単位で処理を考えており、
010001 を 0100 01** で処理してしまい、
44と違う答えを出してしまうそんなテスト不足やデータの想定ミスなんだけど。
/*
* 3.問題点は4ビット(4文字)単位で頭から処理しているからです
*/
問題は単純で、4ビット(4文字)単位で頭から処理しているからです
'文字数分ループする
For n = 1 To Len(str2) Step 4 '4文字(4ビット)単位にループを作る
こんな感じで、4文字単位のループにしているからです。
さて、どうしましょう?
愚痴マガらしい答えは、
相手のプライドを尊重して、自分が00と桁を付ける。
~~~~~~~~~~~~~~
送り側の上位モジュールで桁を調整して、プライドだけは一人前の人にかかわらない。
これも一つの解決方法なんだけど、呼ぶ側は20ヶ所修正、呼ばれる側1ヶ所でしょ
普通は共通モジュールの方に細工するよね。
なんとか作成者を説得します。
01 0001 を 0001 0001 と 送ればいいんだけど、
修正個所多いからできたらそちらでやってもらえるとありがたいんだけど。。。
(※心の中では、なんで下手にでているんだ?と思いつつ、依頼したりする)
作成者は、しょうがない、送ってくれないのなら、自分でそろえますか、
関数の中で細工することにしました。
で、タコの担当者が下記の修正を入れました。
'頭4文字単位かチェックする
n = Len(str2) Mod 4 '4で割ったあまりを計算する
str2 = String(n, "0") & str2 '頭に文字0を追加する
と、こんな感じで、まず、4で割ったあまりをMOD演算子で計算する。
010001だと6文字なので2が計算されます。
次に、計算結果の2文字分0を頭に追加したいので、
String関数を使用してn文字同一の文字を作成して&で連結させました。
String(2, "0") で "00"が生成され&で連結させているので、
00010001 と 文字列が4文字単位になりました。
これで、現在のプログラムで2進010001を16進11に正しく変換可能となります。
だめだコイツ、使えねぇ・・・
えっ、修正されたんじゃない?
確かに、010001だと4で割ると2余って、String(n, "0")で00足すから、
00010001になるんだけど、気が付けよ、あまりが1と3の時は?
例えば、
10101の5桁だと、Mod 4で1 String(n, "0")で"0"しか足さないでしょ、
111の3桁だと、Mod 4 で 3 String(n, "0")で"000"を足すの?
あっ、たまたま、2桁だと動いていたんですね・・・お恥ずかしい。
こんな感じで、言われたデータは直ったように見える、そんな人も居る。
逆の意味、そんな作業者だからこんなバグを作り出すんだろうけど・・・
'頭4文字単位かチェックする
n = Len(str2) Mod 4 '足りない文字数を計算する
If n <> 0 Then
str2 = String(4 - n, "0") & str2 '頭に文字0を追加する
End If
と、修正してみました。
ASP版だけど、
2進数文字列を受け取りHEX16進文字列を返す(頭0を+する)
http://www.ken3.org/cgi-bin/test/test094-2.asp?DATA=111
で、テストできます。(無事7と表示されるか、、、)
まぁ、すごい、小細工ですよね(笑)
その小細工もはじめ間違っていたんだからシャレニならないよね。
/*
* 4.変換ルーチンを修正する
*/
問題があったら、その処置方法もいろいろとあります。
頭0を付けて、データをキレイにそろえて、現在のルーチンを通す手法もあれば、
処理の根本・考え方を変えてみる方法もあります。
※変えると、また、バグを産む、小細工が安全って説もアリだけど。
変換処理をデコボコのデータを後ろから変換するように作り変えてみます。
後ろのビットから、
1 2 4 8 16 32 64 128
とビットを計算していき、文字"1"でたっていたら数値を+する。
そんな作りに変えてみます。
Function STR2toHEX16_B(ByVal str2 As String) As String
Dim strHEX As String
Dim n As Integer 'ループカウンタ
Dim i As Integer 'ループのカウンタ
Dim n8421 As Long '8 4 2 1の数値計算用
Dim nBYTE As Long
strHEX = "" '結果のエリアを初期化する
n8421 = 1 '初期値に1を代入する(下から計算したいので)
nBYTE = 0 '計算用変数を初期化
'文字数分ループする
For n = Len(str2) To 1 Step -1 '後ろからループを作る
'ビットが立っているかチェックする
If Mid(str2, n + i, 1) = "1" Then
nBYTE = nBYTE + n8421 'ビットに対応した数値を+する
End If
'次のビットを計算したいので*2で計算
n8421 = n8421 * 2
Next n
'計算して、数値が完成したので16進文字にしてセットする
strHEX = Hex(nBYTE)
'リターン値をセットして関数を抜ける
STR2toHEX16_B = strHEX
End Function |
文字列を後ろから見るために、逆順のループを作ってみました。
For n = Len(str2) To 1 Step -1 '後ろからループを作る
で、次のポイントが、
'次のビットを計算したいので*2で計算
n8421 = n8421 * 2
2進数は*2で次の位が求められるので、単純にカケテ次の位を計算してます。
If Mid(str2, n + i, 1) = "1" Then
nBYTE = nBYTE + n8421 'ビットに対応した数値を+する
End If
あとは、ビットが立っていたら+しているだけです。
最後はHEX関数で、変換しただけです。
こんな感じで、プログラムを一から見直して、作成してみました。
2進数文字列を受け取りHEX16進文字列を返す(後ろから変換)
http://www.ken3.org/cgi-bin/test/test094-3.asp?DATA=111010
で、テストできます。(6桁の11 1010を変換すると3Aとなるはず?)
/*
* 5.終わりの挨拶
*/
バグの原因から、プログラムの修正方法を書いてみました。
データ長があっていないなら、データの長さを合わせる方法
と
データ長があっていなくても、目的の動作をする、
そんな2点を書いてみました。
どちらがいいかは、一長一短なので、
この関数は修正や影響小さかったので、何とも言えませんが、
テスト時は、いろいろな形のデータが来ることを想定してください。
いちばん簡単なのが、空白やNullなど、何も入っていないときなど・・・
テストデータは汚く、幅広くって感じで、
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
読者の心に残れば、うれしいです。
*私の独り言をうまく消化してくださいね。
三流プログラマーKen3でした。
フィードバック
愚痴系の→[掲示板]←を覗く、質問を書き込む
評価・感想
三流君の主なリンク先
[アクセスランキング]
[サイトマップ]
[リンク先・相互リンク先など]
Ken3の日記(weblog) --
[プログラマー業務の愚痴]
[VBA系の話題]
[ASP系の話題]
[コンビニ系ネタ]
[その他]
その他 宣伝広告