アプリ版:「スタンプのみでお礼する」機能のリリースについて

Excelのマクロで、どうにも理解できない結果に困っております。
If文による大小判定なのですが、同じ判定条件文なのに一枚のシートモジュールに書いたマクロと判定文を標準モジュールに書いてシートモジュールからコールした場合の判定結果が同じ結果になりません。
このような場合には、必ず何処かに単純なミスがあるのが通例ですが、今回は何度見直してもミスが発見できません。
少々分かり難い質問文になりましたが InputBox から入力した数値が指定した範囲にあるか否かの判定をするマクロです。

1.シートモジュール Sheet1 に書いたマクロ (正常動作)

Dim データ総数 As Long
Dim 除外データ数 As Variant
Dim 処理データ数 As Variant
Dim Alm As String

Sub 血圧色分けA()

データ総数 = 300 '仮にデータ総数を300と設定

N1: 除外データ数 = InputBox("除外するデータ数を入力してください" & vbCr & _
"データ範囲は0~" & データ総数 - 1 & "個です" & vbCr & _
"最新データから除外するデータ数より以前のデータを処理します", _
"血圧色分け", 0)

If 除外データ数 = "" Then
MsgBox ("処理をキャンセルします")
GoTo N3

ElseIf IsNumeric(除外データ数) = False Then
Alm = MsgBox("数字を入れてください", vbCritical)
GoTo N1

ElseIf 除外データ数 > データ総数 - 1 Or 0 > 除外データ数 Then
Alm = MsgBox("データ範囲は0~" & データ総数 - 1 & "個です", vbCritical)
GoTo N1

End If

N3: End Sub


2.判定文を標準モジュール Module1 に書いて引数付きでシートモジュール Sheet2 に書いたマクロから引数付きでコールする場合 (動作?)

<Sheet2のマクロ>

Dim データ総数 As Long
Dim 処理項目 As String
Dim 初期値 As Long
Dim キャンセル As Boolean
Dim 除外データ数 As Variant

- - - - - - - - - 
Sub 血圧色分けB()

データ総数 = 300 '仮にデータ総数を300と設定

処理項目 = "除外データ数"

初期値 = 0

Call 除外データ数取得(除外データ数, データ総数, 処理項目, 初期値)

N3: End Sub

- - - - - - - - - 
<Module1のマクロ>

Dim Alm As String

- - - - - - - - - 
Sub 除外データ数取得(A, B, C, D)

'A = 除外データ数
'B = データ総数
'C = 処理項目
'D = 初期値


N1: A = InputBox(C & "を入力してください" & vbCr & _
"データ範囲は0~" & B - 1 & "です" & vbCr & _
"最新データから" & C & "より以前のデータを処理します", C, D)

If A = "" Then
MsgBox ("処理をキャンセルします")
GoTo N3

ElseIf IsNumeric(A) = False Then
Alm = MsgBox("数字を入れてください", vbCritical)
GoTo N1

ElseIf A > B - 1 Or 0 > A Then
Alm = MsgBox("データ範囲は0~" & B - 1 & "個です", vbCritical)
GoTo N1

' ElseIf 除外データ数 > データ総数 - 1 Or 0 > 除外データ数 Then
' Alm = MsgBox("データ範囲は0~" & データ総数 - 1 & "個です", vbCritical)
' GoTo N1

End If

N3: End Sub



 

A 回答 (2件)

厳密に言えば、どちらも正しくありません。


Excelのお節介によって前者は意図したとおりに動き、後者は意図したとおりに動いていないだけです。

前者のマクロでは変数「初期値」はLongで宣言されていますが、後者の方では変数「B」は宣言されていないためVariant(Variant型数値)になっています。
InputBoxで入力された値はどちらもVariant型の変数に代入されていますが、InputBoxが返すのは文字列型ですので、中身は文字列(Variant型文字列)になっています。

前者は、Variant型文字列とLong型の変数を比較しています。
Excelは、比較相手がLong型なので、Variant型文字列を気を利かせて数値として扱います。

後者は、Variant型文字列と、Variant型数値を比較しています。
Excelは、なぜか解りませんが、Variant型文字列とVariant型数値を比較すると、必ずVariant型文字列の方が大きいと判断します。

比較をするときは型を合わせるようにしましょう。
Variantは便利ですが、思いがけないところではまる原因になりやすいです。
最少の修正で後者を前者と同じ動きにしたいのでしたら、以下の様に修正しましょう

Sub 除外データ数取得(A, B, C, D)

Sub 除外データ数取得(A, B As Long, C, D)
    • good
    • 0
この回答へのお礼

>Excelは、なぜか解りませんが、Variant型文字列とVariant型数値を比較すると、必ずVariant型文字列>の方が大きいと判断します。

以前何かで読んだ記憶があるのを思い出しました。
忘れた頃にVBAをやるのですっかり抜けていました。

>Excelのお節介によって前者は意図したとおりに動き、後者は意図したとおりに動いていないだけです。

意図したとおりに動く方はVariant型文字列とLong型の変数を比較していて、意図したとおりに動かない方はVariant型文字列とVariant型数値を比較しているんですね。

はまってしまった理由のひとつは、エディター画面でデバッグする時、マウスカーソルを当てた時に表示される変数の値はLong型もVariant型数値も同じ整数で表示され、型の区別が付かないためだと思います。
見た目は全く同じものを判定しているのに結果が違う。ウー何故って感じでした。

問題の判定文のところではVariant型文字列に入っているのは整数のみなので CLng 等を使用して型を変換して比較するのが間違いのない方法でしょうか。

ElseIf CLng(A) > CLng(B) - 1 Or 0 > CLng(A) Then
Alm = MsgBox("データ範囲は0~" & B - 1 & "個です", vbCritical)
GoTo N1

すっきり解決しました。ありがとうございました。

お礼日時:2013/02/13 13:07

インプットボックスの後に



  Debug.Print TypeName(A), TypeName(B)

と入れて走らせてみると、原因がわかります。

答えを言ってしまうと・・変数AはがString型で見られていますね。
このInputBoxは文字列型で返してくるようです。
なので、数値としての大小を比べられていない状態ですね。

とりあえずの対策。
文字列型が返るなら、数値型に変換しちゃえ、ってことで、
  ElseIf Val(A) > B - 1 Or 0 > Val(A) Then
Val関数で変換しちゃうと上手くいきそうですよ。
多少強引ですけどね^^;
    • good
    • 0
この回答へのお礼

>文字列型が返るなら、数値型に変換しちゃえ、ってことで、
  ElseIf Val(A) > B - 1 Or 0 > Val(A) Then

Val関数は便利ですね。その他にも CLng とかで型変換すれば上手く行きそうです。

お礼日時:2013/02/13 11:19

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A