- ベストアンサー
【Excel VBA】コードの書き方「AまたはBではなかったら…」
Excel2003を使用しています。 マクロで、「選択した範囲で、A列-C列、または、F列-H列が0じゃなかったら、その行をコピーする」という処理をしたいのですが、どのようにコードを書いたらいいでしょうか? 当初は、「A列-C列が0じゃなかったら…」と条件がひとつだけで、そのときは、下記のコード(一部記載)で問題なく処理できていたのですが、条件をもうひとつ追加したら、エラーは出ないものの、結果が反映されなくなってしまいました。 マクロ勉強中ですので、ここはこんなふうにと指摘していただけると助かります。よろしくお願いします。 「A列-C列が0じゃなかったら…」 With Sheets("Sheet1") For m = i To k If .Cells(m, 1) - .Cells(m, 3) <> 0 Then .Range(.Cells(m, j), .Cells(m, l)).Copy ↓ 「A列-C列、または、F列-H列が0じゃなかったら…」 If( .Cells(m, 1) - .Cells(m, 3) <> 0 Or .Cells(m, 6) - .Cells(m, 8) <> 0) Then ( i, j, k, l で、それぞれ、選択範囲の1行目、1列目、最終行、最終列を取得しています。)
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
こういう問題、小生も、悩まされています。 (A=0でかつB=0)以外、つまり、A,Bいづれにかに、何がしか値が入っていれば・・・ としたい時には、(A<>0 or B<>0)とするのですよね。 従って、本件の問題は、スクリプトは、正しいのではないか、使い方に問題があるのではないか、と思うのです。 > i, j, k, l で、それぞれ、選択範囲の1行目、1列目、最終行、最終列を取得しています。 ----選択範囲は、その都度、決めているようです。 >If( .Cells(m, 1) - .Cells(m, 3) <> 0 Or .Cells(m, 6) - .Cells(m, 8) <> 0) Then ----しかし、判定は、常に、A,C,F,Hの値を見ています。 (何も、入力されていないと言うのは、値が「0」と同じです。) A-Cの範囲を選んだ場合、F-Hに値(0以外)が入っていれば、A=C=0であっても、コピーされます。 唯一、コピーを実施しないのは、A=C=F=H=0(空白を含む)の時です。 もし、これが、正しい推測であれば、サジェスチョンは、選択した範囲に 即した、判定をするということです。 選択した範囲のアクティブセルの列番号は、 activecell.columnで 入手できます。また、選択した範囲の行数、列数は、Variant変数に 選択した範囲を代入することで構成されるメモリ上の配列から求めます。 ---------------------------------- Sub Test() Dim myArray As Variant 'i=選択範囲の1行目 'j=選択範囲の1列目 'k=選択範囲の最終行 'l=選択範囲の最終列 i = ActiveCell.Row '選択範囲の左上の行番号 j = ActiveCell.Column '選択範囲の左上の列番号 myArray = Selection.Value 'メモリ上に配列を持ってくる R = UBound(myArray, 1) '選択範囲の行数 C = UBound(myArray, 2) '選択範囲の列数 k = i + R - 1 l = j + C - 1 With Sheets("Sheet1") For m = i To k If l < 5 Then If (.Cells(m, 1) - .Cells(m, 3) <> 0) Then .Range(.Cells(m, j), .Cells(m, l)).Copy .Cells(m, 11) End If If j > 5 Then If (.Cells(m, 6) - .Cells(m, 8) <> 0) Then .Range(.Cells(m, j), .Cells(m, l)).Copy .Cells(m, 11) End If Next End With End Sub 選択範囲の行数、列数を知るのに、Variant変数経由でやっていますが、 もっと、簡便に知る方法があれば、そちらを使った方が良いです。 小生、止む無くこの方法でやっています。
その他の回答 (6)
- Wendy02
- ベストアンサー率57% (3570/6232)
こんばんは。Wendy02です。 うっかり、私は、見過ごしていたことで、ちょっと書かせていただきます。 If( .Cells(m, 1) - .Cells(m, 3) <> 0 Or .Cells(m, 6) - .Cells(m, 8) <> 0) Then なんとなく、違和感があって見ていたのですが、よく考えてみると、基本的なことで、コンピュータのプログラムとしては、抜け落ちがあります。 「.Cells(m, 1)」これらの数値が、何かということなのです。 ワークシート上の数値というのは、みんなDouble型なのです。おまけに、そのまま引き算してしまっているから、合わない可能性は十分にあります。このコードは、結果的には、0を求めるのに他ならないわけです。それを、単に、Double型で計算しても、実務上は、数値によっては、うまくいくほうが不思議なぐらいです。 こういう場合は、「型キャスト」というテクニックを使ってしまったほうがよいのです。 「型キャスト」とは、精度を落とすことを言います。ですから、Double 型の数値は、Long型の変数に入れたときに、精度が落ちます。それを利用します。ただし、小数点があるときは、小数点固定法や整数法で計算します。Excelのセルの場合は、一旦、時間値などは、.Textプロパティで取ってから、型の変換をしてもよいです。 Dim a As Long, b As Long, c As Long, d As Long, '厳密には、一旦、セルの値の型が、Double型であることを検査します。 a= .Cells(m, 1).Value b =.Cells(m, 3).Value c =.Cells(m, 6).Value d =.Cells(m, 8).Value If (a - b) <> 0 Or (c - d) <> 0 Then ・ ・
お礼
Wendy02 さん、おはようございます。 何度もアドバイスをいただき、ありがとうございます。 質問に関することのみでなく、最後まで丁寧に説明してくださいますので、大変参考になります。 今回は、簡単にできるだろうと思っていたことが、意外と手こずったりして、私にとっては、いろんな意味で勉強にもなりました。 私は問題が解決しても、数日は締め切らないようにしているのですが、それが良かったようです。ありがとうございました<(_ _)>
- Dxak
- ベストアンサー率34% (510/1465)
> 選択した範囲には、A列、C列とF列、H列が同時に含まれることはなく、 > どちらか一方なので、単純に Or でつなげればいいかなと思い、コード > を書いてみたのですが、うまくいきませんでした。 選択した範囲?セル指定ではなくて、Offsetプロパティを使用した方がよくない? 選択したところから、相対位置で参照できるし・・・
お礼
Dxak さん、おはようございます。 再度、アドバイスをいただき、ありがとうございます。 >選択した範囲?セル指定ではなくて、Offsetプロパティを使用した方がよくない? >選択したところから、相対位置で参照できるし・・・ 今回の場合は、あるデータに対して、何度もこのマクロを実行しながら、新たにデータを完成させます。選択する範囲はマクロを実行するたびに変えますので、その都度、範囲を指定する方法にしています。 この選択した範囲に対して、さらに細かく条件をつけることで、解決できました。 ありがとうございました<(_ _)>
A.No4のものです。補足です。 選択範囲の列数、行数は、下記で求めることができます。 ' http://www.geocities.co.jp/Bookend-Kenji/8629/yohaku/sample.htm 選択範囲列数 = Selection.Columns.Count 選択範囲行数 = Selection.Rows.Count こちらを、使う方がスマートです。
お礼
Rich53 さん、おはようございます。 再度、アドバイスをいただき、ありがとうございます。 教えていただいたURL拝見しました。 このURLのようにサンプルが記載されていると、マクロ勉強中の私にとって、とてもわかりやすく、参考になります。 最後までご丁寧にありがとうございました<(_ _)>
- Dxak
- ベストアンサー率34% (510/1465)
> 「A列-C列、または、F列-H列が0じゃなかったら…」 と言うのは A列-C列が0以外または、F列-H列が0以外 の場合と A列-C列が0またはF列-H列が0の場合、以外 の場合との日本語の取り方の違いが前回の論理式の違いになってます 私は、前者の様に読めたので、問題ないと思ったのですが・・・ #2さんは、後者のように読めたみたいです Not( .Cells(m, 1) - .Cells(m, 3) = 0 Or .Cells(m, 6) - .Cells(m, 8) = 0) を変換していくと Not( .Cells(m, 1) - .Cells(m, 3) = 0) And Not(.Cells(m, 6) - .Cells(m, 8) = 0) ↓ ( .Cells(m, 1) - .Cells(m, 3) <> 0) And (.Cells(m, 6) - .Cells(m, 8) <> 0) と、この間の結果になるわけです 論理式では、主流がNot、Or、Andを使いそのまま実施するので、あまり変換をしませんが・・・論理回路では、頭で考えたNot、Or、AndをNAND、NORに置き換えて安価で高速な設計していきますので、こういう論理変換は良く出てくるのですが・・・プログラムでは、あまりしませんね で、上記の日本語の説明は実際どういうものなの?
補足
Dxak さん、こんばんは。 目に留めていただき、ありがとうございます。 >A列-C列が0以外または、F列-H列が0以外 >の場合と >A列-C列が0またはF列-H列が0の場合、以外 >の場合との日本語の取り方の違いが前回の論理式の違いになってます 指摘されるまで気づきませんでしたが、私は前者の意味で、「A列-C列、または、F列-H列が0じゃなかったら…」と書いていました。 選択した範囲には、A列、C列とF列、H列が同時に含まれることはなく、どちらか一方なので、単純に Or でつなげればいいかなと思い、コードを書いてみたのですが、うまくいきませんでした。 違う方法でも検討してみようと思っているので、こうしてみたら?というものがありましたら、アドバイスいただけると助かります。
- Wendy02
- ベストアンサー率57% (3570/6232)
こんにちは。Wendy02です。 前回の私の回答は、Not で書いたので間違えたようですから、前の質問側に回答をつけておきました。ですから、そちらをみていただきたいですが、ひとつだけこちらに加えておきますと、 「A列-C列、または、F列-H列が0じゃなかったら…」 一旦、変数を置くなり、If や ElseIf で、分けても良いのではありませんか? あえて、Or, And でつなげると、論理積、論理和、排他論理和など、いくら慣れていても、よほど自信がある方ならともかく、シミュレートしないと分からなくなることがあります。
お礼
Wendy02 さん、こんにちは。 こちらでも、回答いただきまして、ありがとうございます。 Or や And でつなげて、いろいろ考えていると、なんだか混乱してきます。 Wendy02 さんのおっしゃるように、違う方法で処理したほうが、解決が早いような気がしてきました。 アドバイス、ありがとうございました。
- ham_kamo
- ベストアンサー率55% (659/1197)
書き方自体は間違ってないように見えるのですが…。 とりあえずデバッグしてみましょう。やり方はわかりますか? VBAの画面で、If文の左の方(枠の外)をクリックするか、If文の上にカーソルがある状態でF9を押すと、そこにブレークポイントが設定されます。 その状態でマクロを実行すると、ブレークポイントで処理が中断されます。 そこで右クリックして「ウォッチ式の追加」を選び、mやSheets("Sheet1").Cells(m,1)、Sheets("Sheet1").Cells(m,3)などを追加すると、それらの値を調べることができます。(ウォッチウィンドウに表示されます) また、それらのウォッチ式を追加した状態で、F8キーを押すとステップ実行(一行ごとに実行しては止まる)できるので、マクロを実行するのにF5キーでなくF8キーで実行していくと、それらの値がどう変化するかも見れます。 とりあえず、そうやって何かおかしいところがないか調べてみてはいかがでしょうか。
お礼
ham_kamo さん、こんにちは。 回答ありがとうございます。 デバッグしてみました。 恥ずかしながら初めてしたのですが、おかしいところはないように感じました。 Or でつなげると、Or 以前の条件も無視(?)されてしまって、単に選択した範囲をコピーするだけになってしまいます。(私にとっては、これが不思議でしょうがないのですが…) No.2のWendy02 さんの回答にも書いてありましたが、論理和・論理積ってムズカシイですね(>_<) Or を使わない何か別の方法でやったほうが、解決が早いような気がしてきました。。。
お礼
Rich53 さん、こんばんは。 回答ありがとうございます。 >本件の問題は、スクリプトは、正しいのではないか、使い方に問題があるのではないか、と思うのです。 別の方法でやってみようかと思い始めていたところでしたが、「使い方に問題」という言葉で、さらに細かく条件をつけて、試してみました。 また、教えていただいたコードもヒントになり、選択範囲に対しても、さらにIFで条件をつけることで、解決できました。行き詰っていたところでしたので、大変助かりました。 ありがとうございました!