質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

4回答

1860閲覧

vbaでインデックスエラーがわからない

jun_endo

総合スコア56

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2018/07/24 04:41

編集2018/07/24 04:53

###やりたいこと
CADのデータを解析して、別のシートに出力する。

ある特定の線分のデータから、縦の線と横の線を分類する。
(x、yの座標から判断する)
例)横線の場合

開始の位置が(1,1)
終了の位置が(1,5)

  つまり横線はxの値が変わらない。
縦の線も同様に分類する。

その後、交点を求め、その交点の中から、
四角形になる条件の持つ四つの交点を見つけて、
また別の処理をする。

というものです。

###プログラム
プログラムが醜いのはわかっております
これでもかなり可視性を上げたほうです
プログラムの改善点などがありましたら教えてください

vba

1Sub 寸法取得() 2 3'シート数を数える 4sn = Worksheets.Count 5 6 7 8Dim 横線(), 縦線(), 石番号() As Variant 9DimAs Integer,As Integer,As Integer 10 11row = 2:= 0:= 0:= 0 12 13'動的配列 14ReDim Preserve 横線(), 縦線(), 石番号() 15 16'シートを指定する(アクティブ) 17With Sheets(sn) 18 19 'シートの空白行まで 20 Do While .Cells(row, 1) <> "" 21 22 'セルの中身が石番号なら別の処理をする 23 If .Cells(row, 1) <> "●18石番号" Then 24 25 '各画層の始点と終点のx,yの値を代入する 26 始点x = .Cells(row, 2): 始点y = .Cells(row, 3) 27 終点x = .Cells(row, 4): 終点y = .Cells(row, 5) 28 29 'xの始点と終点の値が同じならそれは縦線 30 If 始点x = 終点x Then 31 '縦線は(y始点,y終点,xの座標)のコンマ区切りの文字列 32 縦線() = 始点y & "," & 終点y & "," & 始点x 33 '(xは終始同じ数値なので始点のみ記述) 34=+ 1 35 ReDim Preserve 縦線() 36 Else 37 'yの始点と終点の値が同じならそれは横線 38 If 始点y = 終点y Then 39 '横線は(x始点,x終点,yの座標)のコンマ区切りの文字列 40 横線() = 始点x & "," & 終点x & "," & 始点y 41 '(yは終始同じ数値なので始点のみ記述) 42=+ 1 43 ReDim Preserve 横線() 44 End If 45 End If 46 Else 47 '石番号は(x座標,y座標,石番号)のコンマ区切りの文字列 48 石番号() = .Cells(row, 2) & "," & .Cells(row, 3) & "," & .Cells(row, 7) 49=+ 1 50 ReDim Preserve 石番号() 51 End If 52 row = row + 1 53 Loop 54End With 55 56Dim 固定比較, 流動比較, 交点() As Variant 57'基準となる変数=固定比較 58'比較時に基準とならない変数=流動比較 59 60DimAs Integer, n_2 As Long, xn As Long 61 62= 0 63 64ReDim Preserve 交点(0) 65 66'縦線を中心に交点を求めていく 67For n = 0 To- 1 68 '縦線の文字列をコンマで分割する 69 固定比較 = Split(縦線(n), ",") 70 For n_2 = 0 To- 1 71 '横線の文字列をコンマで分割する 72 流動比較 = Split(横線(n_2), ",") 73 74 '交点が縦と横の線それぞれの範囲内に存在するか調べる 75 If 固定比較(0) <= 流動比較(2) And 流動比較(2) >= 固定比較(1) And _ 76 流動比較(0) <= 固定比較(2) And 固定比較(2) >= 流動比較(1) Then 77 ' 78 '交点は(x座標,y座標)のコンマ区切りの文字列 79 交点() = 固定比較(2) & "," & 流動比較(2) 80=+ 1 81 ReDim Preserve 交点() 82 End If 83 Next n_2 84Next n 85 86 87Dim x軸() As Variant 88 89ReDim x軸(0) 90xn = 0 91 92'交点と交点を結ぶ線分の探索 93For n = 0 To- 1 94 固定比較 = Split(交点(n), ",") 95 96 For n_2 = n + 1 To- 1 97 流動比較 = Split(交点(n_2), ",") 98 99 '横線の条件に一致しているかを調べる 100 If 固定比較(1) = 流動比較(1) Then 101 102 '数値の大小を調べて始点、終点を決める 103 If 固定比較(0) < 流動比較(0) Then 104 'x軸は(始点x,始点y,終点x,終点y)のコンマ区切りの文字列 105 x軸(xn) = 交点(n) & "," & 交点(n_2) 106 Else 107 x軸(xn) = 交点(n_2) & "," & 交点(n) 108 End If 109 xn = xn + 1 110 ReDim Preserve x軸(xn) 111 End If 112 Next n_2 113Next n 114 115Dim 交四点() As Variant, fn As Long 116fn = 0 117ReDim 交四点(0) 118 119'横線を決めたので、それぞれの横線の長さが同じものを探索する 120For n = 0 To xn - 1 121 固定比較 = Split(x軸(n), ",") 122 For n_2 = n + 1 To xn - 1 123 'MsgBox (UBound(x軸)) 124 流動比較 = Split(x軸(n_2), ",") 125 126 'x座標が同じものを探索 127 If 固定比較(0) = 流動比較(0) And 固定比較(2) = 流動比較(2) Then 128 If 固定比較(1) < 流動比較(1) And 固定比較(3) < 流動比較(3) Then 129 130 '交四点は(上辺に当たるx軸,底辺に当たるx軸)のコンマ区切りの文字列 131 交四点(fn) = x軸(n) & "," & x軸(n_2) 132 Else 133 交四点(fn) = x軸(n_2) & "," & x軸(n) 134 End If 135 136 fn = fn + 1 137 ReDim Preserve x軸(fn) 138 End If 139 Next n_2 140Next n

###エラー内容
エラーの内容は、

インデックスが有効範囲にありません。

というものでした、
非常に簡単なエラーと感じたのですが、
エラーの箇所をよく見てみると、

vba

1 'MsgBox (UBound(x軸)) 2 流動比較 = Split(x軸(n_2), ",") ##ここでインデックスエラーが発生する

上記のところで発生しているのですが、

x軸という配列の添え字が(136)の時に発生していました。
しかし、x軸配列の要素を挿入しているときは、
確実に136よりも大きい添え字を相手にしているので
インデックスの範囲外には、なっていないので困惑しております。

そのため、自分の知識だけでは、わからなく困っています。

どなたか教えてください。

意味が不明だったり、もっと必要な情報があった場合は、
編集依頼で教えてください。

プログラムとセルのデータを書いておきますので、
それぞれで、実際に実行してエラーを確認していただけたらうれしいです。

プログラム
https://teratail.com/questions/137538
セルデータ
https://teratail.com/questions/137543

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

jawaさんのおっしゃる通りコードの一番下から4行目があやしいと思います。
ここでx軸()の配列数を変更するのはなぜですか?

VBA

1ReDim Preserve x軸(fn)

コードを読む限りここで本当に変更したかったのは
交四点()の配列数なのではないですか?

的外れでしたらすみません。

投稿2018/07/24 06:15

KiyomiH

総合スコア40

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun_endo

2018/07/24 06:33

おっしゃるとうりでした、 しかし、次はレスポンスが切れてしまい、 VBAの高速化を図っています。
guest

0

ベストアンサー

コードをすべて追ったわけではないのですが、エラーになりそうな要因として気になった点がありましたのでアドバイスさせていただきます。
はずしていたらすみません。


y_waiwaiさんへの回答で
>エラーの行の一つ上で、MsgBox(Ubound(x軸))で、インデックスの最大値を確認したところ、"96825"と表示されました。
と記載されていますが、ループ内でメッセージ表示していますので、n_2が136になるまで何回もメッセージ表示されるコードになっていたものと思います。

本当にエラーが発生したn_2 = 136のループ回でUbound(X軸)を確認されましたか?

同ループの下のほうで、条件次第でX軸()配列をRedimしている箇所もあります。
ReDim Preserve x軸(fn)
ここで配列要素を135以下に更新してしまっていたりはしないでしょうか?


推測でのアドバイスで申し訳ありませんが、可能性として確認してみてください。

投稿2018/07/24 05:39

編集2018/07/24 05:41
jawa

総合スコア3013

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun_endo

2018/07/24 06:32

確かに、上記のところが間違っていました、 x軸 を 交四点 に変更しました。 ただ、その後の処理が、ウィンドウのタイトルに"応答なし" 表示されてしまいますしまいます。 以前私は、同じような状態が発生したときに、 ループのインクリメントがされていないために、 無限ループとなってしまい、応答が切れてしまいました。 しかし今回は、要素の都合上、for文を用いています、 無限ループはおろか、 ついさっきまで、エラーが発生していたので、 エラー発生個所よりも前の段階では、 無限ループは発生していないと判断できます。 よって、エラーの発生したところで、 膨大な量のデータ処理をしているため、 応答が切れたんだと思います。 この場合DoEventsを使うのが適切なのでしょうか? その場合は、どこに配置するのが適切でしょうか? もしくは、VBAの高速化で何か適切な方法は あるのでしょうか? 今の段階では、 Application.ScreenUpdating で、画面の表示を制御しているだけで、 ほかのことは何もやっておりません。
jawa

2018/07/24 11:53

仮にxn=96825とすると、nループで96825周くらいループする中でn_2ループが(n + 1)~96825くらいのループをすることになります。 96825+96824+96823+...+1=40億以上という途方もない回数のループが行われることになります。 ExcelVBAはもともとハイスペックではありませんから、ちょっと負荷が大きすぎる処理ですね。 ちなみに当方の環境では単純にこの回数の空ループを回すだけで数分の時間がかかりました。 動いてさえいるのなら待っていればいずれ終わるのだと思いますが、無駄なループをしなくて済むような仕組みを考えたほうが良さそうですね。
guest

0

x軸という配列の添え字が(136)の時に発生していました。

しかし、x軸配列の要素を挿入しているときは、
確実に136よりも大きい添え字を相手にしているので
インデックスの範囲外には、なっていないので困惑しております。

あなたはそういってるんだけど、そのコードはそう言ってません。
そのエラーが出るときに、そうなっているのかいないのかをしっかりチェックしましょう

投稿2018/07/24 05:00

y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun_endo

2018/07/24 05:13

エラーの行の一つ上で、 MsgBox(Ubound(x軸)) で、インデックスの最大値を確認したところ、 "96825"と表示されました。 なので、インデックスの範囲内ではあると判断しました。 その場合でも、有効範囲ではないということでしょうか? その場合は、どのような文法を記述するのが適切でしょうか? 逆に、なぜ136でエラーが発生するのでしょうか? 私は、x軸の配列に、別の変数をsplitで分割するのが、 インデックスに関係しているのではないかとも、 考えています。 その方向でも、何かわかることがあれば教えてください。
y_waiwai

2018/07/24 05:23

その"96825"という値は正しいんでしょうか x軸という配列はなにを指しているのか、配列数はなにを表してるのかを考えましょう
ExcelVBAer

2018/07/24 05:27

デバッグにMsgBoxを使ってると非効率です。 この機会に、 ブレークポイント、イミディエイトウィンドウ、ローカルウィンドウ、 とかを覚えるのが、 問題解決の近道だと思います。
sysjojo

2018/07/24 05:51

>エラーの行の一つ上で、 >MsgBox(Ubound(x軸)) >で、インデックスの最大値を確認したところ、 OK押しました? ExcelVBAerさんおっしゃるようにDebug.Printでイミディエイトウィンドウに出した方が分かりやすいですね。
guest

0

たまに、実際のエラーの行と、デバッグて反転表示される行がずれる場合があるので、前後のコードをチェックしてみる必要もあります。

例えば、

vba

1 流動比較 = Split(x軸(n_2), ",") 2 3 'x座標が同じものを探索 4 If 固定比較(0) = 流動比較(0) And 固定比較(2) = 流動比較(2) Then 5 If 固定比較(1) < 流動比較(1) And 固定比較(3) < 流動比較(3) Then

2x軸(n_2)が "" だったりすると、
次行の流動比較(0)でインデックスエラーになります。

投稿2018/07/24 05:54

hatena19

総合スコア33620

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun_endo

2018/07/24 06:38

x軸の直前の要素は、 確実に、自分が指定した、形式の要素が入っていましたので、 流動比較でのインデックスエラーではなかったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問