• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:VBAで配列内のエラー値の取得)

VBAで配列内のエラー値の取得

このQ&Aのポイント
  • VBAで配列内のエラー値の取得方法について質問があります。エクセルのシートのセル範囲を配列に取り込み処理を行っていますが、データにエラー値が含まれる場合、型が一致せずエラーが発生します。現在は関数を使用してエラー値を文字列に変換する方法を実装していますが、より簡単な方法はないでしょうか?
  • 現在、VBAでエクセルのシートのセル範囲を配列に取り込んで処理を行っていますが、データにエラー値が含まれると型が一致せずにエラーが発生してしまいます。そこで、エラー値を文字列に変換する方法について教えてください。
  • VBAを使用してエクセルのシートのセル範囲を配列に取り込み処理を行っているのですが、データにエラー値が含まれると型が一致せずエラーが発生してしまいます。現在は関数を使用してエラー値を文字列に変換していますが、もっと簡単な方法があれば教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.5

>配列に取り込んでいるので.text では文字列化できないのです。 問題としているところがやっと理解できました。<m(__)m> そうですね、 セルの値(CellやRangeオブジェクト)ならTextプロパティがありますが むろん、配列変数にはTextプロパティはありまぜん。 エラーかどうかの判定と "#DIV/0!"や"#N/A"といった人間の理解できる文字列を得るには お使いの関数Emsgのような作りこみが避けられません。 更に、エラー値の取りうる値は 列挙されたものだけとは限りませんので厄介です。 繰り返しになりますが エラー処理はより上流で行うのが鉄則です(と思っています)ので、 私だったら 'MyV = buf(0).Value といったコードで配列変数に格納するのではなく 地道に次のようなコードを使います。 Sub testa()  Dim buf(1) As Range  Dim MyV  Dim CntR As Long  Dim CntC As Long    Set buf(0) = Selection  MyV = buf(0)    For CntR = 1 To UBound(MyV, 1)   For CntC = 1 To UBound(MyV, 2)    If IsError(buf(0).Cells(CntR, CntC)) = True Then     MyV(CntR, CntC) = buf(0).Cells(CntR, CntC).Text    Else     MyV(CntR, CntC) = buf(0).Cells(CntR, CntC).Value    End If   Next CntC  Next CntR End Sub

emaxemax
質問者

お礼

何度もありがとうございます。 MyV = buf(0).Value と MyV = buf(0) の違いは配列の要素が値かRangeかの違いと考えてよいですか? そして、その要素がエラーであればTEXTで、そうでなければVALUEで置き換えているということですね?

その他の回答 (8)

  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.8

>MyV = buf(0).Value と >MyV = buf(0) の違いは >配列の要素が値かRangeかの違いと考えてよいですか? はい。 提示されたコードを流用したため Dim MyV と記述しました。 as以降が省略されていますので、 定義上は、Variantです。 Set buf(0) = Selection MyV = buf(0) これは言うまでもなく Dim buf(1) As Range Set buf(0) = Selection ですから buf(0)の中身は、Rangeですし、 MyV = buf(0) の場合の左辺の中身もRangeです。 別な質問に対する返答でも触れたんですが Variantの多様や Dim MyV といった記述は、コードを読みにくくするだけでなく バグの温床になります。 他方、 >MyV = buf(0).Value とした場合の 左辺の中身は配列です。

emaxemax
質問者

お礼

何度も何度もありがとうございました。

  • m3_maki
  • ベストアンサー率64% (296/460)
回答No.7

横から失礼します。 > いったん配列に入れてしまうとできません。 ということであれば、もう1度適当なセルに書き込んであげるとか。 Sub test0001()   Range("Z1") = myW(1, 2))   MsgBox Range("Z1").Text   Range("Z1") = "" End Sub

emaxemax
質問者

お礼

ありがとうございます。 それも一つの解決策ですね。

  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.6

もし、 'MyV = buf(0).Value が譲れないのであれば、 For i = LBound(myV, 1) To UBound(myV, 1)     For n = LBound(myV, 2) To UBound(myV, 2)       If IsError(myV(i, n)) Then         myV(i, n) = Emsg(myV(i, n)) この時にEmsg関数を使うのではなく myV(i, n)に格納したセルのtextプロパティを取得する対応でも いいんじゃないかと思います。

emaxemax
質問者

お礼

ありがとうございました。

  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.4

とれとも、 Sub test005()   MsgBox Selection(1, 2).Text End Sub でしょうか。

emaxemax
質問者

お礼

ありがとうございました。

  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.3

やりたいことがよくわかりませんが 次のようなコードなら期待の内容ですか? Sub test002()  Dim myW As Range  Set myW = Selection  If IsError(myW) = True Then    MsgBox (myW.Text)  End If End Sub 'または Sub test003()  Dim MyRange As Range  Dim TgtCell As Range    Set MyRange = Range("A1:C4")    For Each TgtCell In MyRange   If IsError(TgtCell) = True Then     MsgBox (TgtCell.Text)   End If  Next End Sub

emaxemax
質問者

お礼

何度もありがとうございます。 ありがとうございます。 質問文にも書いておりますが、.text でエラー値を文字列化できるのはRangeの値だららですよね? 今回は対象が大きいため、配列に取り込んでいるので.text では文字列化できないのです。 だから Function Emsg(ByVal x As Variant) As String   Select Case x     Case CVErr(xlErrDiv0): Emsg = "#DIV/0!"     Case CVErr(xlErrNA): Emsg = "#N/A"     Case CVErr(xlErrName): Emsg = "#NAME?"     Case CVErr(xlErrNull): Emsg = "#NULL!"     Case CVErr(xlErrNum): Emsg = "#NUM!"     Case CVErr(xlErrRef): Emsg = "#REF!"     Case CVErr(xlErrValue): Emsg = "#VALUE!"   End Select End Function で文字列化しているのですが、これをもっと簡単にできないかと思って質問しています。

emaxemax
質問者

補足

現在行っているコードです。 Sub 選択範囲データ比較()   Dim myV, myW   Dim buf(1) As Range   Dim i As Long, n As Long, j As Long, k As Long   Dim ws(1) As Worksheet   Set ws(0) = ActiveSheet   Set buf(0) = Selection   myV = buf(0).Value   If MsgBox(buf(0).Address & " と開いている他のBOOKを参照しますか?" _   & vbCrLf & "" _   & vbCrLf & "他のBOOKなら「はい」" _   & vbCrLf & "このBOOKなら「いいえ」", vbYesNo + vbQuestion) = vbYes Then     Application.Dialogs(xlDialogActivate).Show     If ws(0).Parent.Name = ActiveSheet.Parent.Name Then       If MsgBox("他BOOKではないですがよろしいですか?", vbOKCancel + vbQuestion) = vbCancel Then         Exit Sub       End If     End If   End If      On Error Resume Next   Set buf(1) = Application.InputBox(Prompt:="セルを選択してください。", Type:=8)   On Error GoTo 0      If buf(1) Is Nothing Then     Exit Sub   End If   Set ws(1) = ActiveSheet   myW = buf(1).Value   If UBound(myV, 1) <> UBound(myW, 1) Then     MsgBox "行数が異なります。", vbCritical     Exit Sub   ElseIf UBound(myV, 2) <> UBound(myW, 2) Then     MsgBox "列数が異なります。", vbCritical     Exit Sub   End If      For i = LBound(myV, 1) To UBound(myV, 1)     For n = LBound(myV, 2) To UBound(myV, 2)       If IsError(myV(i, n)) Then         myV(i, n) = Emsg(myV(i, n))       End If       If IsError(myW(i, n)) Then         myW(i, n) = Emsg(myW(i, n))       End If       If myV(i, n) <> myW(i, n) Then         If IsNumeric(myV(i, n)) And IsNumeric(myW(i, n)) Then           If Application.Round(myV(i, n), 13) <> Application.Round(myW(i, n), 13) Then             j = j + 1           Else             k = k + 1           End If         Else           j = j + 1         End If       End If     Next n   Next i   If j > 0 Then     MsgBox j & " 個、値の相違があります。" _     & vbCrLf & "" & k & " 個、浮動小数点演算誤差があります。", vbCritical   ElseIf k > 0 Then     MsgBox k & " 個、浮動小数点演算誤差があります。", vbExclamation   Else     MsgBox ws(0).Name & " vs " & ws(1).Name & "" _     & vbCrLf & "同一データです。" _     & vbCrLf & "" _     & vbCrLf & "対象行数:" & UBound(myV, 1) & "" _     & vbCrLf & "対象列数:" & UBound(myV, 2) & ""   End If End Sub Function Emsg(ByVal x As Variant) As String   Select Case x     Case CVErr(xlErrDiv0): Emsg = "#DIV/0!"     Case CVErr(xlErrNA): Emsg = "#N/A"     Case CVErr(xlErrName): Emsg = "#NAME?"     Case CVErr(xlErrNull): Emsg = "#NULL!"     Case CVErr(xlErrNum): Emsg = "#NUM!"     Case CVErr(xlErrRef): Emsg = "#REF!"     Case CVErr(xlErrValue): Emsg = "#VALUE!"   End Select End Function

  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.2

そもそもシート上に埋めた計算式がエラーとなる可能性があるのなら、 =IFERROR といった関数を使い、 セルにエラー値を埋めない対応を行っておくのが一般的と思います。 つまり、エラー処理はより上流で行っておくべきものと思います。 そうではなく、 エラー値の埋まったセルを対象にせざるを得ない事情があり、かつ、 マクロがエラーを起こし、中断してしまうことが問題であれば、 それは、 On Errorステートメントを使ったエラー処理を行っていないからです。 http://officetanaka.net/excel/vba/tips/tips104.htm あたりがわかりやすいと思います。 このエラー処理を組み込むことが事情があって難しいのであれば、 私なら、 対象セル全数の中にエラー値があるかどうかを事前にチェックし、 あれば補正するとか、メッセージを表示して抜ける対応を行います。 つまり、より上流でチェックします。 言い換えれば、 エラー処理を行わないまま下流にきているので、 苦戦し、作りこまなければならない事態を招いているように 読み取れます。

emaxemax
質問者

お礼

>エラー値の埋まったセルを対象にせざるを得ない事情があり はい、その通りです。やりたいことは二つの大きなセル範囲の差異を調べることです。 しかも、エラー値の違いも判定しなければいけないのでOn Errorステートメントで回避するわけにはいかないのです。 ありがとうございました。

  • kkkkkm
  • ベストアンサー率66% (1719/2589)
回答No.1

単純に文字列になればいのであれば CStr(myW(1, 2)) でエラー値の文字列になります…エラー 2042とかのですが…。

emaxemax
質問者

お礼

エラーナンバーなんですね。 ありがとうございます。

  • skp026
  • ベストアンサー率45% (1010/2238)
回答No.1

以下がご要望の記事のように思います。 https://qiita.com/nukie_53/items/6c2d9d4699149bebe863 抜粋 ここから============ 該当のエラー値の取得方法ですが、ExcelのタイプライブラリにはExcel.XlCVErrorという列挙型が定義されています。 この列挙型の値をCVErr関数に渡すことで、該当するセルのエラー値を取得できます。 ここまで============ ご要望と違いましたらごめんなさい。

emaxemax
質問者

お礼

ありがとうございます。 でも使い方がよくわかりませんでした。すみません。

関連するQ&A