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

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

ただいまの
回答率

90.52%

  • VBA

    1786questions

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

  • Excel

    1527questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 304

jun_endo

score 45

やりたいこと

CADのデータを解析して、別のシートに出力する。

ある特定の線分のデータから、縦の線と横の線を分類する。
(x、yの座標から判断する)
例)横線の場合
  
開始の位置が(1,1)
終了の位置が(1,5)

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

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

というものです。

プログラム

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

Sub 寸法取得()

'シート数を数える
sn = Worksheets.Count



Dim 横線(), 縦線(), 石番号() As Variant
Dim 横 As Integer, 縦 As Integer, 石 As Integer

row = 2: 縦 = 0: 横 = 0: 石 = 0

'動的配列
ReDim Preserve 横線(横), 縦線(縦), 石番号(石)

'シートを指定する(アクティブ)
With Sheets(sn)

    'シートの空白行まで
    Do While .Cells(row, 1) <> ""

        'セルの中身が石番号なら別の処理をする
        If .Cells(row, 1) <> "●18石番号" Then

            '各画層の始点と終点のx,yの値を代入する
            始点x = .Cells(row, 2): 始点y = .Cells(row, 3)
            終点x = .Cells(row, 4): 終点y = .Cells(row, 5)

            'xの始点と終点の値が同じならそれは縦線
            If 始点x = 終点x Then
                '縦線は(y始点,y終点,xの座標)のコンマ区切りの文字列
                縦線(縦) = 始点y & "," & 終点y & "," & 始点x
                '(xは終始同じ数値なので始点のみ記述)
                縦 = 縦 + 1
                ReDim Preserve 縦線(縦)
            Else
                'yの始点と終点の値が同じならそれは横線
                If 始点y = 終点y Then
                    '横線は(x始点,x終点,yの座標)のコンマ区切りの文字列
                    横線(横) = 始点x & "," & 終点x & "," & 始点y
                    '(yは終始同じ数値なので始点のみ記述)
                    横 = 横 + 1
                    ReDim Preserve 横線(横)
                End If
            End If
        Else
            '石番号は(x座標,y座標,石番号)のコンマ区切りの文字列
            石番号(石) = .Cells(row, 2) & "," & .Cells(row, 3) & "," & .Cells(row, 7)
            石 = 石 + 1
            ReDim Preserve 石番号(石)
        End If
        row = row + 1
    Loop
End With

Dim 固定比較, 流動比較, 交点() As Variant
'基準となる変数=固定比較
'比較時に基準とならない変数=流動比較

Dim 交 As Integer, n_2 As Long, xn As Long

交 = 0

ReDim Preserve 交点(0)

'縦線を中心に交点を求めていく
For n = 0 To 縦 - 1
    '縦線の文字列をコンマで分割する
    固定比較 = Split(縦線(n), ",")
    For n_2 = 0 To 横 - 1
        '横線の文字列をコンマで分割する
        流動比較 = Split(横線(n_2), ",")

        '交点が縦と横の線それぞれの範囲内に存在するか調べる
        If 固定比較(0) <= 流動比較(2) And 流動比較(2) >= 固定比較(1) And _
           流動比較(0) <= 固定比較(2) And 固定比較(2) >= 流動比較(1) Then
                '
                '交点は(x座標,y座標)のコンマ区切りの文字列
                交点(交) = 固定比較(2) & "," & 流動比較(2)
                交 = 交 + 1
                ReDim Preserve 交点(交)
        End If
    Next n_2
Next n


Dim x軸() As Variant

ReDim x軸(0)
xn = 0

'交点と交点を結ぶ線分の探索
For n = 0 To 交 - 1
    固定比較 = Split(交点(n), ",")

    For n_2 = n + 1 To 交 - 1
        流動比較 = Split(交点(n_2), ",")

        '横線の条件に一致しているかを調べる
        If 固定比較(1) = 流動比較(1) Then

            '数値の大小を調べて始点、終点を決める
            If 固定比較(0) < 流動比較(0) Then
                'x軸は(始点x,始点y,終点x,終点y)のコンマ区切りの文字列
                x軸(xn) = 交点(n) & "," & 交点(n_2)
            Else
                x軸(xn) = 交点(n_2) & "," & 交点(n)
            End If
            xn = xn + 1
            ReDim Preserve x軸(xn)
        End If
    Next n_2
Next n

Dim 交四点() As Variant, fn As Long
fn = 0
ReDim 交四点(0)

'横線を決めたので、それぞれの横線の長さが同じものを探索する
For n = 0 To xn - 1
    固定比較 = Split(x軸(n), ",")
    For n_2 = n + 1 To xn - 1
        'MsgBox (UBound(x軸))
        流動比較 = Split(x軸(n_2), ",")

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

                '交四点は(上辺に当たるx軸,底辺に当たるx軸)のコンマ区切りの文字列
                交四点(fn) = x軸(n) & "," & x軸(n_2)
            Else
                交四点(fn) = x軸(n_2) & "," & x軸(n)
            End If

            fn = fn + 1
            ReDim Preserve x軸(fn)
        End If
    Next n_2
Next n

エラー内容

エラーの内容は、

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


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

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

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

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

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

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

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+2

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


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

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

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


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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/24 15:32

    確かに、上記のところが間違っていました、
    x軸 を 交四点 に変更しました。
    ただ、その後の処理が、ウィンドウのタイトルに"応答なし"
    表示されてしまいますしまいます。
    以前私は、同じような状態が発生したときに、
    ループのインクリメントがされていないために、
    無限ループとなってしまい、応答が切れてしまいました。
    しかし今回は、要素の都合上、for文を用いています、
    無限ループはおろか、
    ついさっきまで、エラーが発生していたので、
    エラー発生個所よりも前の段階では、
    無限ループは発生していないと判断できます。
    よって、エラーの発生したところで、
    膨大な量のデータ処理をしているため、
    応答が切れたんだと思います。

    この場合DoEventsを使うのが適切なのでしょうか?
    その場合は、どこに配置するのが適切でしょうか?
    もしくは、VBAの高速化で何か適切な方法は
    あるのでしょうか?
    今の段階では、
    Application.ScreenUpdating
    で、画面の表示を制御しているだけで、
    ほかのことは何もやっておりません。

    キャンセル

  • 2018/07/24 20:53

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

    キャンセル

+2

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/24 14:13

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

    キャンセル

  • 2018/07/24 14:23

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

    キャンセル

  • 2018/07/24 14:27

    デバッグにMsgBoxを使ってると非効率です。

    この機会に、
    ブレークポイント、イミディエイトウィンドウ、ローカルウィンドウ、
    とかを覚えるのが、
    問題解決の近道だと思います。

    キャンセル

  • 2018/07/24 14:51

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

    キャンセル

+2

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

ReDim Preserve x軸(fn)


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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/24 15:33

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

    キャンセル

0

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

例えば、

        流動比較 = Split(x軸(n_2), ",")

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


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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/24 15:38

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

    キャンセル

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

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • VBA

    1786questions

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

  • Excel

    1527questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。