【2025年9月】
マクロを「作るとき」と「読むとき」では、頭の使い方が違います。作るのは、例えるならパーツを組み立てるような作業ですね。もちろん、頭の中の設計図も必要です。対して、コードを読むときは、パーツよりも全体の構成を把握することが重要です。もし、マクロがエラーになったら、そのマクロで何の処理をしているのかを読まなければなりません。エラーの箇所がピンポイントで分かっているのなら簡単ですが、デバッグに不慣れなビギナーは、どこの何が間違っているのかを"発見"することに難儀します。ちなみにデバッグ作業はミスの発見が8割です。ミスの理由さえ判明すれば、修正するのは意外と簡単なことが多いです(当社比)。さて、マクロがエラーになったら、どうしますか?できれば、AIにズバッと解決してもらいたいですよね。じゃ、マクロがエラーになったとき、プロンプトに何と書きますか?ただ「エラーを直して」だけでは、絶対に無理です。せめて、コードのどこがエラーになったのか、くらいは伝えましょう。次の簡単なケースでやってみます。
Sub Sample1() Dim tmp As Variant tmp = Split("100,田中,東京", ",") Range("A1") = Left(tmp(1), 1) End Sub
このマクロは、Split関数で"100,田中,東京"を分割し、2番目の値(田中)から左1文字を抜き出してセルA1に代入します。これは、正常に動作します。では、次のように変えてみます。
Sub Sample1() Dim tmp As Variant tmp = Split("100,田中,東京", ",") Range("A1") = Left(1, tmp(1)) End Sub
Left関数に指定した引数の順番が間違っています。もちろん、実行するとエラーです。
さぁ、問題はここです。AIのプロンプトには「どこでエラーになった(止まった)」かを指定します。
マクロが「Range("A1") = Left(1, tmp(1))」でエラーになった。理由は?
「Range("A1") = Left(1, tmp(1))」のエラー理由は、LEFT関数の引数の順序が間違って いるためです。 正しい構文は「Left(文字列, 文字数)」です。 「Left(1, tmp(1))」だと「1」が文字列、「tmp(1)」が文字数になり、型が合わずエラーに なります。 正しくは「Left(tmp(1), 1)」のように、 最初の引数に文字列、2番目に文字数を指定してください。
正しく理由を解説されて、修正案も提示してくれました。このやり取りが成功したのは、プロンプトに記述した「Range("A1") = Left(1, tmp(1))」部分に間違いがあったからです。では、次のケースではどうでしょう。
Sub Sample1() Dim tmp As Variant tmp = Split("田中", ",") Range("A1") = Left(tmp(1), 1) End Sub
Left関数の引数は正しいです。しかし、Split関数で分割する文字列が"田中"しかありません。この結果は、要素がひとつだけの配列になります。
先と同じように、マクロは「Range("A1") = Left(tmp(1), 1)」で止まっています。
マクロが「Range("A1") = Left(tmp(1), 1)」でエラーになった。理由は?
主な原因は、tmp(1)の中身が「空(未定義)」または「数値」など、Left関数が扱えない型 になっている可能性が高いです。 Left関数は「文字列型」のみ有効なので、tmp(1)が未定義・数値・配列・Nothingなどの場合、 エラーになります。 例: tmpが配列として宣言されていない tmp(1)が未代入 tmp(1)が数値やオブジェクト 対策例: Range("A1") = Left(CStr(tmp(1)), 1) または、tmp(1)の中身を事前にDebug.Print等で確認してください。
言ってることは正しいです。Left関数がエラーになるケースなんて、それくらいしかありません。とはいえ、今度は候補が複数あります。書かれている内容を理解できれば「あ、あれかも」と気づくでしょうけど、マクロが読めないビギナーには難しいのでは。ちなみに、対策例として提示された「Range("A1") = Left(CStr(tmp(1)), 1)」は、CStr関数を使ってtmp(1)の内容を"文字列化"しています。今回のケースでは的外れです。では、プロンプトにマクロのコード全体を記述したら。
Sub Sample1()
Dim tmp As Variant
tmp = Split("田中", ",")
Range("A1") = Left(tmp(1), 1)
End Sub
上記のマクロが「Range("A1") = Left(tmp(1), 1)」でエラーになった。理由は?
エラーの理由は、tmp = Split("田中", ",")で分割結果が1要素(tmp(0)のみ)となり、 tmp(1)が存在しないため「インデックスが範囲外」エラーが発生します。 Split("田中", ",") の結果: tmp(0) = "田中" tmp(1) は存在しない(エラー) 解決策: 分割後の要素数を確認してからアクセスしてください。
お見事です。これなら理由もよく分かります。つまり、こういうことです。エラーで止まったのは「Range("A1") = Left(tmp(1), 1)」です。でも、その原因はSplit関数で分割した元の文字列(今回は"田中")です。そこが知りたかったんです。だったら、AIにマクロ全体を伝えなければならないです。だけど、みなさんが実務で使っているマクロって、こんな短いですか?んなこたぁないですよね。これの数十倍もダラダラ無駄なことが書かれていますよね。それを、そっくりプロンプトに書くんですか?もし、プロシージャの中から別のプロシージャをCallしていたら、そしたら、モジュール全体を書くんですか?それは、無理がありますよね。でも、全体が分からないと、いくらAIとはいえ原因を言い当てることはできません。推測で、いくつかの候補を提示するだけです。
マクロがエラーになったとき、その理由と修正方法を、AIが適切に提示してくれたら嬉しいです。でも、そのためには、マクロの全体像を伝えなければなりません。ジレンマですね。では、別のコードで試してみましょう。いくらなんでも、Left関数は簡単すぎました。下記は「[作って]CSVを読み込むマクロ」の"特定の行だけ読み込む"で、AIに作ってもらったマクロです。正常に動作します。
Sub ImportTanakaData() Dim ws As Worksheet Dim csvPath As String Dim csvLine As String Dim arr As Variant Dim outRow As Long Dim fso As Object, ts As Object Set ws = ActiveSheet csvPath = "C:\data\data07.csv" Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(csvPath, 1) outRow = 1 ' ヘッダ行を読み込む If Not ts.AtEndOfStream Then csvLine = ts.ReadLine arr = Split(csvLine, ",") ws.Range("A" & outRow).Resize(1, UBound(arr) + 1).Value = arr outRow = outRow + 1 End If ' データ行を読み込む Do While Not ts.AtEndOfStream csvLine = ts.ReadLine arr = Split(csvLine, ",") If arr(1) = "田中" Then ws.Range("A" & outRow).Resize(1, UBound(arr) + 1).Value = arr outRow = outRow + 1 End If Loop ts.Close End Sub
CSVファイルは、こんな感じです。この中から「名前」が"田中"の行だけをシートに読み込みます。
本来は正しく動作するマクロを、今回はわざとエラーにさせます。先に種明かしをしますが、CSVを次のようにイタズラしました。
おそらく「If arr(1) = "田中" Then」部分でエラーになるはずです。
いくら何でも、このイタズラをAIが気づくとは思えません。先と同じように、コード全体とエラーの箇所をプロンプトに記述してみます。
(上記のコード) 上記のマクロが「If arr(1) = "田中" Then」でエラーになった。理由は?
「If arr(1) = "田中" Then」でエラーになる理由は、arr配列の要素数が2未満の場合 (つまり、arr(1)が存在しない場合)に「インデックスが有効範囲外」エラーが発生するためです。 これは、CSVの行が空行だったり、カンマ区切りの数が足りない場合に起こります。 対策例: If UBound(arr) >= 1 Then If arr(1) = "田中" Then ws.Range("A" & outRow).Resize(1, UBound(arr) + 1).Value = arr outRow = outRow + 1 End If End If このように、arr(1)にアクセスする前に要素数を確認することでエラーを防げます。
げげっ!バレたwしかも、対策も完璧。なかなか、やりますね。じゃあ、もっと酷いイタズラをしちゃいます。ちょっと、あり得ないような。ちなみに、CSVの空行は削除しときます。
The error occurs because you are trying to assign a 1-dimensional array (arr) directly to a multi-cell range, but Excel expects a 2-dimensional array for such assignments. The Split function returns a 1D array, but Range.Value for multiple cells requires a 2D array (even for a single row). To fix this, you need to convert arr to a 2D array before assignment. For example: CAUTION: Please carefully review the generated VBA code before running it! Dim arr2D As Variant arr2D = Application.Transpose(Application.Transpose(arr)) ws.Range("A" & outRow).Resize(1, UBound(arr) + 1).Value = arr2D This wraps your 1D array into a 2D array that Excel can write to the worksheet.
なぜか英語のままw Google翻訳で日本語にします。
このエラーは、1次元配列(arr)を複数セル範囲に直接代入しようとしているにもかかわらず、 Excelではそのような代入には2次元配列が想定されているため発生します。 Split関数は1次元配列を返しますが、複数セルのRange.Value関数は(単一行であっても) 2次元配列を必要とします。 この問題を解決するには、代入前にarrを2次元配列に変換する必要があります。例: 注意:生成されたVBAコードを実行する前に、よく確認してください。 Dim arr2D As Variant arr2D = Application.Transpose(Application.Transpose(arr)) ws.Range("A" & outRow).Resize(1, UBound(arr) + 1).Value = arr2D これにより、1次元配列がExcelがワークシートに書き込める2次元配列に変換されます。
う~ん、ちゃんとResizeプロパティで2次元配列にしてますけど。はい、ちょっと悪質でしたね。原因は、実はエラーメッセージに書かれていました。
シートを保護して、そもそもセルに書き込めないようにしていたんです。はい?エラーメッセージを見れば分かるって?いやいや、今回はAIがどう判断するかの検証です。人間が分かるってのは、また別の話です。だから、責めないでw
今回あらためて検証したかったのは、AIにエラーの原因を調べてもらうために、エラーになって止まっている行だけでなく、マクロ全体や環境なども伝えなければならない、ってことです。だけど、それが実務では難しいです。ある程度、VBAの知識があって、Excelの基礎も理解していて、デバッグの経験もある人なら、エラーの原因に"当たりを付ける"こともできるでしょう。しかし、ビギナーのみなさんは、どうでしょう。今はAIがあるから、もうExcelやVBAのことなんか学習しないでいいや、な~んて堕落した考えがあったら、AIは何の手助けもしてくれません。そんな人はきっと「ああ、やっぱAIなんか使えねーな」って思うんでしょうね。違うんですよ。使えないのは、あなたです。