
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
No.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)
>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
すっきり解決しました。ありがとうございました。
No.1
- 回答日時:
インプットボックスの後に
Debug.Print TypeName(A), TypeName(B)
と入れて走らせてみると、原因がわかります。
答えを言ってしまうと・・変数AはがString型で見られていますね。
このInputBoxは文字列型で返してくるようです。
なので、数値としての大小を比べられていない状態ですね。
とりあえずの対策。
文字列型が返るなら、数値型に変換しちゃえ、ってことで、
ElseIf Val(A) > B - 1 Or 0 > Val(A) Then
Val関数で変換しちゃうと上手くいきそうですよ。
多少強引ですけどね^^;
>文字列型が返るなら、数値型に変換しちゃえ、ってことで、
ElseIf Val(A) > B - 1 Or 0 > Val(A) Then
Val関数は便利ですね。その他にも CLng とかで型変換すれば上手く行きそうです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
同じ文字列なのにfalseになってしまいます。
Excel(エクセル)
-
VBA:同じ文字列データの比較がうまくいかない例
Excel(エクセル)
-
VBA シートをコピーする際に Copyメソッドは失敗しましたのエラーが出てしまいます
Visual Basic(VBA)
-
-
4
Excel 大小比較演算子による「文字」の比較結果
Excel(エクセル)
-
5
エクセルVBAで、条件に一致するセルへ移動
Excel(エクセル)
-
6
初歩的な事だと思います。 Sub または Function が定義されていません。
Visual Basic(VBA)
-
7
VBAのプログラムで、DIAG = 1# / A(L, L) や R(
その他(プログラミング・Web制作)
-
8
イミディエイトウインドウの最高表示数は199行?
Excel(エクセル)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
教えて下さい
-
メモ帳(テキストデータ)をExc...
-
配列でデータが入っている要素...
-
【エクセル】測定時間がバラバ...
-
多量のSUMIF式を軽くしたい
-
javaでDBからデータを取ってき...
-
<VB>String→Object
-
ページ数を求めたい
-
ウィンドウ枠の固定を行の2箇所...
-
EXCEL VBA FREQUENCY関数での...
-
Excelのマクロでワードのテキス...
-
S9タイプからXタイプにデータ...
-
VBAでのリストビューにおけるド...
-
ユーザーフォームのテキストボ...
-
VB6でCSVの取込をする
-
ACCESS VBA インデックスが有効...
-
C# ソケット通信でデータ受信時...
-
あんまり考えたくないけど
-
シリアル通信におけるバイトデ...
-
C言語を用いて、GNUPLOTでリア...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
教えて下さい
-
【エクセル】測定時間がバラバ...
-
メモ帳(テキストデータ)をExc...
-
配列でデータが入っている要素...
-
<VB>String→Object
-
二分探索の平均探索回数
-
多量のSUMIF式を軽くしたい
-
EXCELVBAでSQLserverからデータ...
-
この行は既に別のテーブルに属...
-
ユーザーフォームのテキストボ...
-
VBA 空白セルを削除ではない方...
-
特定のデータの抽出方法を教え...
-
パースとはなんですか?
-
C# ソケット通信でデータ受信時...
-
エクセルで2つの時系列のデー...
-
[C言語] コメント文字列を無視...
-
Accessで該当データにフラグを...
-
カンマからスラッシュに
-
C# でDataTableの更新を高速化...
-
アクセス2000で画像データ...
おすすめ情報