evaluateを使ったユーザ定義関数でエラー

このQ&Aのポイント
  • 個人用マクロブックの標準モジュールにFunction Eval(str As String) As Single Eval = Evaluate(str) Application.Volatile End Function と記入し、文字列を数式に変換する関数Eval()を定義しました。
  • B7に入力された値によって計算式を振り分ける数式を設定していましたが、振り分け先の式がIF(MONTH(Q1)=5,ROW(),COLUMN())の場合にvalueエラーが発生しました。
  • IF(MONTH(Q1)=5,,COLUMN())やIF(MONTH(Q1)=5,100,COLUMN())といった式ではエラーは発生せず、IF(MONTH(Q1)=5,"100",COLUMN())のように文字列を含むとエラーが発生します。
回答を見る
  • ベストアンサー

evaluateを使ったユーザ定義関数でエラー

個人用マクロブックの標準モジュールに Function Eval(str As String) As Single Eval = Evaluate(str) Application.Volatile End Function と記入し、文字列を数式に変換する関数Eval()を定義しました。 それを使用して、B7に入力された値によって、計算式を振り分ける数式を =PERSONAL.XLSB!Eval(VLOOKUP($B7,$AQ$2:$BA$53,2,0)) とし、計算を振り分けていたのですが 振り分け先の式(vlookupで検索した式)が以下の式の時valueエラーになってしまいました。 IF(MONTH(Q1)=5,ROW(),COLUMN()) 尚 IF(MONTH(Q1)=5,,COLUMN()) IF(MONTH(Q1)=5,100,COLUMN()) IF(MONTH(Q1)=5,SUM(A1:A2),COLUMN()) としたときはエラーになりません IF(MONTH(Q1)=5,"100",COLUMN())はエラーになります。 何故エラーになるのか、修正方法はどうしたらいいのかわかりません。 ご存知の方いらっしゃいましたら、どうかご教授願います。

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

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

>IF(MONTH(Q1)=5,index($1:$1048576,ROW()-1,COLUMN()-1),COLUMN()) もともと、この数式はアブナイですね。ユーザー定義関数の中で、無限ループが発生しています。結果が再帰的に、再計算させていますので、このような数式は書かないほうがよいのですが、数式上では、循環参照です。なぜ、ROW() や、COLUMN()では、無限ループにならないのかは、良く分かりませんが、たぶん、配列の中に逃がしているのだと思います。以下のような数式の場合、自己の数式位置を参照しないようにしています。また、一回きりなら、無限ループから抜ける方法はあるのですが、常時使う関数ですと、その方法がありません。これに関しては、無理だと思います。 しかし、数式が多岐になるなら別ですが、この数式ですと、完全なユーザー定義関数で書いても良いような気がしますね。 Public Function MyFunc(arg1 As Variant, Optional i As Long = 1, Optional j As Long = 1) Dim r As Range, r1 As Range Dim buf As Variant If VarType(arg1) = vbBoolean Then  Set r = Application.Caller  If i = 0 And j = 0 Then '循環参照を避ける    MyFunc = CVErr(xlErrNA)    Exit Function  End If  If arg1 Then   Set r1 = r.Offset(i, j)   buf = ActiveSheet.Cells(r1.Row, r1.Column)  Else   buf = r.Column  End If End If If Not IsError(buf) Then  MyFunc = buf End If Set r = Nothing End Function '// 数式例:(ただし、以下は、アドインにしています) =MyFunc(MONTH($Q$1)=ROW(A5),-1,-1)

k-logi
質問者

お礼

うわあ…無限ループ発生ですか。 どうやらこのユーザー定義関数を普段使いにするのは、わたしにはとても難易度が高いようです。 しかしおかげさまでこの方法の検討に区切りがつきました。 二度も丁寧に教えて下さって本当にありがとうございました! お陰さまで大変助かりました。 これからも一層精進します。

その他の回答 (2)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

こういうユーザー定義関数は、かなり特殊だと思います。 ふつうは、名前登録から作りますが、別のセキュリティ・メッセージが出てきてしまいます。たぶん、ご質問者さんは、VBAには、ある程度、腕に覚えがあるようにお見受けしますので、私が知っている注意点を、書かせていただきます。 余計なお世話だと思えば、無視していただいて良いです。ふつうは、必要のない知識です。 まず、ワークシートで使うユーザー定義関数の戻り値は、本来はVariant型なのです。その理由は、本格的には、CVErr を利用し、エラー値を吐き出すからです。必ず、数値しか返さないなら、Double型になります。 Public キーワードは、あまり意味がありませんが、見かけだけの理由で、ワークシートで使うということになると、頭につけるという習慣があるそうです。(長い間、私は疑問に感じていましたが、その分野の偉い人がそういうなら仕方がありません。) 次に、str という引数名はやめたほうがよいです。strというのは、VBA/VB関数名です。予約語とはならないまでも、やめたほうがよいです。 次に、一旦、引数を、buf というものに入れて、出力させないほうがよいと思います。ご存知かとは思いますが、ワークシートのCOLUMN関数やROW関数は、配列で出力しますから、一旦、配列から値を取り出したほうがよいかと思います。 Volatileは、引数を再定義すれば、再計算しますから、必要がない限りは、いれなくてもよいです。あまり習慣化しないほうがよいです。ワークシート全体に及ぶようになります。 >=PERSONAL.XLSB!Eval(VLOOKUP($B7,$AQ$2:$BA$53,2,0)) ふつうは、グローバル・関数として、特定のブックから呼び出すような関数にはしませんから、それは、アドイン型で作ります。頭にファイル名が不要になります。 Public Function Eval(strTxt As String) As Variant  Dim buf As Variant  buf = Evaluate(strTxt)  If IsArray(buf) Then '←本来は、IsError を先頭にして、エラーを分岐する。   Eval = buf(1)  Else   Eval = buf  End If  Application.Volatile '←本来は、あまり使いません End Function

k-logi
質問者

補足

丁寧なご回答ありがとうございます! 関数を定義しなおしたところ、お陰さまでエラーがなおりました。 初めてユーザー定義関数を使ってみたのですが、ワークシート関数のデータ型等大変勉強になりました。 直ったところで振り分け先の式 IF(MONTH(Q1)=5,ROW(),COLUMN()) を IF(MONTH(Q1)=5,index($1:$1048576,row()-1,column()-1),COLUMN()) にしてみたのですが、今度はこの式の真の場合がvalueエラーになりました。 row()-1,column()-1にあたるセルには数値が入っています。 …index関数の中にrow()やcolumn()を入れたのがまずかったのでしょうか… 質問続きですみません。

  • keithin
  • ベストアンサー率66% (5278/7940)
回答No.1

Function Eval(str As String) As Single を Function Eval(str As String) As Variant に変えてみてください。 個別関数の内部的な事情で,どうやら返ってくるモノが微妙に違うものがあるようです。 元のsingleの状態で,「"100"」なら(暗黙の型変換が作動して)計算できたと思いますが「abc」では文字列を数値指定の関数の値として格納しようとしてエラーになります。の延長線と考えられます。

k-logi
質問者

お礼

回答ありがとうございます。 なるほど~ワークシートで使うときもデータ型には十分気をつけねばいけないのですね…。

関連するQ&A

  • ユーザー定義関数をボタンに登録したい

    数式のエラーを回避するユーザー定義関数を作りPERSONAL.xlsに登録しました。 その後アドインに保存して、関数の挿入ダイアログボックスのユーザー定義関数から選んで使用していますが、頻繁に使用するのでボタンに登録したいのです。 どのようにすればいいのでしょうか? ネットで検索して色々やってみてるのですが分かりません。 ボタンのマクロの登録で「PERSONAL.xla!vlookupエラー回避」と直接打ち込んで登録してみましたが、実際にボタンをクリックすると「コンパイルエラー End Subが必要です」というエラーメッセージが出ます。 どこをどうすればいいのか教えてください。よろしくお願いします。 Sub vlookupエラー回避() ' ' vlookupエラー回避 Macro ' マクロ記録日 : 2006/7/25 ユーザー名 : ******** ' Function myVLookup(Rg As Range, Area As Range, col As Integer, opt As Integer) Dim vlk As Variant vlk = Application.VLookup(Rg, Area, col, opt) If IsError(vlk) Then vlk = "" End If myVLookup = vlk End Function

  • ユーザ定義関数がうまく動きません。

    ユーザ定義関数がうまく動きません。 2月のA1セル値が1になっていたりします。 どこがおかしいのかわかりません。解決方法を教えていただけませんでしょうか。 よろしくお願いします。 【シートの設定】 シート名は1月・・・12月です。 各シートの A1セルは「=sheetname()」 B1セルは「月のチェックシート」 が入っています。 【VBAの設定】 Function SheetName() As String 'Application.Volatile If Len(ActiveSheet.Name) = 3 Then SheetName = Left(ActiveSheet.Name, 2) Else SheetName = Left(ActiveSheet.Name, 1) End If End Function

  • Excelのユーザー定義関数について。

    ネットで調べて「アルファベットのみを半角にする」というユーザー定義関数を発見し使用していますが、 この関数にある特定の文字を変換する条件を追加することはできますでしょうか。 例えば、リンゴ という文字がセル内にある場合、ミカン に変換されて表示されるという条件を下記のユーザー定義関数に加える事ができますか。 もしくは、新たに別のユーザー定義関数を作るしかないのでしょうか。アドバイスよろしくお願いします。m(_ _ )m Function ASC_A(str As String) As String Dim i As Integer For i = 1 To Len(str) If Mid(str, i, 1) Like "[a-zA-Z]" Then Mid(str, i, 1) = StrConv(Mid(str, i, 1), vbNarrow) End If Next ASC_A = str End Function

  • ユーザー定義関数にて

    色つきセルの合計を数えるユーザー定義関数を使用していますが 普通の関数のように、セルに変更等ですぐに更新してくれればいいのですが 表示は前回のままです。(ですのでF9を押しています) 計算ではちゃんとした数字になっているのですが 更新が遅くて変更されません。 (セル範囲は縦で30個ぐらいです) すぐに更新するいい方法はないでしょうか? ご経験者の方々、知識ある方々の ご意見やアドバイスなどをよろしくお願いします。 色つきセルのカウント Function CountColor(計算範囲, 条件色セル) Application.Volatile CountColor = 0 For x = 1 To 計算範囲.Rows.Count If 計算範囲.Rows(x).Interior.ColorIndex = 条件色セル.Interior.ColorIndex Then CountColor = CountColor + 1 End If Next End Function

  • エクセル 複数シート( VLOOKUP ユーザー定義関数

    複数シート(範囲)を指定できるVLOOKUP関数をユーザー定義で作りたいと思ってます。下記のコードではうまく動かないので教えてください。 Function VLOOKUPM(検索値 As Variant, 対象シート As String, 対象セル As Range, 列番号 As Integer) As Variant Dim i As Integer Dim r As Range Dim sh As Variant Application.Volatile sh = Split(対象シート, ",") For i = 0 To UBound(sh) Set r = Sheets(sh(i)).Range(対象セル) If 検索値 = r Then VLOOKUPM = r.Offset(0, 列番号) Exit Function End If Next End Function

  • ユーザー定義関数で辞書のような使用法

    Excel2000ユーザー定義関数で、 参照された文字列を、任意のフォルダ内にあるエクセルファイルから、 Vlookup関数のような形で引っ張ってくることは出来るでしょうか? どうしても、ファイルパスを指定出来ません。 ex) Function kanjiname(セル) Application.Volatile Dim myRange As Range Set myRange = Workbooks("C:\辞書ファイル.xls").Worksheets("Sheet1").Range("C1:C9") kanjiname = Application.VLookup(セル, myRange, 5, False) という感じにしたいのです。 開いていないファイルをOpenしても無理ですし、 どうすればいいのでしょうか。 End Function

  • またまた エクセルのユーザー定義で

    前回以下のようなコードを教えていただきましたが、この変換を複数列で使えるようにするにはどうしたらいいのでしょうか? D,G,N,Q,X,AA,の列に効かせたいのですが。 Private Sub worksheet_change(ByVal Target As Range) If Intersect(Target, Columns(1)) Is Nothing Or Selection.Count <> 1 Then Exit Sub Dim str As String str = Target Application.EnableEvents = False If Target <> "" Then If Len(str) = 7 Then Target = Left(str, 5) & "A" & Mid(str, 6, 1) & "-" & Right(str, 1) Else Target = Left(str, 5) & "A" & Mid(str, 6, 2) & "-" & Right(str, 1) End If End If Application.EnableEvents = True End Sub

  • ユーザー定義関数の再計算

    ユーザー定義関数を作りました。 ところが、この関数が自動再計算をしてくれません。 どうしたら自動再計算するようになるのでしょうか? よろしくお願いします。 ちなにこの関数は、自分のシートのB2とsheet1~sheet4のB9を比較して、正しければB9の4つ右のセルの値を合計して返すものです。 =SheetLook($B$2,"sheet1,sheet2,sheet3,sheet4",B9,4) コードです。 Function SheetLook(参照元 As Variant, 比較対象シート As String, 比較対象セル As Range, 参照セル位置 As Integer) As Variant   Dim i As Integer   Dim rng As Range   Dim sss As Variant   Dim kei As Variant   Dim cnt As Integer   sss = Split(比較対象シート, ",")   kei = 0   cnt = 0   For i = 0 To UBound(sss)     Set rng = Sheets(sss(i)).Range(比較対象セル.Address)     If 参照元 = rng Then       kei = kei + rng.Offset(0, 参照セル位置)       cnt = cnt + 1     End If   Next   If cnt <> 0 Then     SheetLook = kei   Else     SheetLook = ""   End If End Function

  • vbaにおいて、セルのエラー検出に関して

    vbaにてセルに入力する数式のエラー検出に関して教えてください。 iserror関数で検出できない数式を簡単に検出する方法ありませんか? sub test() dim str as string str=" C2*C3* " cells(5,7).value=str end sub 簡単なVBAのコードですが、*の右側はセル相対参照もセル絶対参照も数値も入っていませんので、数式としてはエラーです。 strの値を(5,7)のセルに放り込んだら、vbaのエラーで停止してしまいます。 かといって、iserror()を使って、 sub test() dim str as string str="C2*C3*" if iserror(str)=true then else cells(5,7).value=str end if end sub としても、エラーをはじいてくれず、VBAでもエラーを出力してしまいます。 力業で、strの数式エラーをはじくしか方法はないのでしょうか? インターネットを調べているのですが、的を射た答えが出てきません。 どなたか詳しい方ご教示ください。

  • vlookupで「'」で囲った名前定義がエラーに

    エクセル、vlookupについての質問です 別ブックの、都度都度違うシートから値を引用するためのvlookup関数を以前作成し、 今回修正を加えようとするとエラーになります 具体的には 名前で以下の二つを定義 名前(W):■定義□引用前 参照範囲(R):=INDIRECT("'["&計算式!$D$3&".xls]"&計算式!$D$8&"'!"&計算式!$D$10) ■定義□引用後 参照範囲(R):=INDIRECT("'["&計算式!$D$3&".xls]"&計算式!$D$8&"'!"&計算式!$D$11) (「計算式」というシートのD3に引用するブック名、D8にシート名、D10とD11にvlookupで引用する範囲の座標をそれぞれ指定) =VLOOKUP($D$6,'■定義□引用前':'■定義□引用後',4,0) という式の列番号を変更しようとすると、 「入力した数式は正しくありません」 というエラーが出ます 既に入力されている式はちゃんと引用され表示もされているのに、 変更しようとするとエラーが出ます 正直全く意味がわかりません どなたかご教示願えますでしょうか

専門家に質問してみよう