解析其参数的函数

时间:2017-04-05 11:28:58

标签: excel vba excel-vba udf

我有一个用VBA编写的UDF,我从我的工作表调用。该函数有3个参数:Function CONCATIF(arg1 As Range, arg2 As Boolean, Optional arg3 As Range) As Variant

UDF需要知道arg2的公式,即在将arg2评估为TRUEFALSE之前拦截arg2。要做到这一点,我使用了Application.Caller.Formula,它给了我(最简单的形式)"=CONCATIF(arg1, arg2, arg3)"(或代替,arg3) ),)) 然后我可以通过简单地使用Split(Application.Caller.Formula, ",")

获得arg 2

虽然

有几个我想解决的问题
  • 以逗号分隔意味着我的所有参数都不能包含逗号,而这些逗号可能必须
  • 公式可能是嵌套的,例如=SUM(1,IF(CONCATIF(arg1, arg2, arg3)="a",1,0)),所以我不知道我的split数组中的哪一项是arg2。 (我认为这应该很容易解决:在字符串中找到CONCATIF并切断开始,计算其后的开/关括号,直到打开=关闭,然后切断结束。
  • 参数可能是公式本身; arg1可以是对范围的引用,而不是实际范围。
  • 棘手:CONCATIF可能在1个公式中多次出现,但是使用标准字符串搜索我会总是拿起第一个(如果1个公式中有多个,我可能只需要返回错误,因为我无法想到如何解决这个问题)

所以我想要的是:从调用者单元格中获取正确的CONTCATIF()公式,然后将三个参数解析为数组中的3个字符串的一般方法。作为参考,这是我的代码(对不起,命名与问题有点不同)

Public Function CONCATIF(checkRange As Range, testFunction As Boolean, Optional concatRange As Range) As Variant

Dim concatArray() As Variant
Dim formulaText As String, formulaParts() As String, formulaTest As String
Dim topLeft As Range, subCell As Range
Dim newTest As String
Dim results() As Boolean, result As Boolean
Dim loopval As Long
'''
'input checking
'''
If concatRange Is Nothing Then
    concatArray = checkRange
ElseIf Not (checkRange.Cells.Count = concatRange.Cells.Count And checkRange.Rows.Count = concatRange.Rows.Count And checkRange.Rows.Count = 1) Then
    CONCATIF = CVErr(xlErrValue)
    Exit Function
Else
    concatArray = concatRange.Value2
End If
'''
'Extract test function
'''
formulaText = Application.Caller.Formula
formulaParts = Split(formulaText, ",") 'Assumes 1)no commas 2) formula isn't nested 3) formula doesn't contain nested functions
formulaTest = formulaParts(1) 'get the test function as a string to be evaluated
Set topLeft = checkRange.Cells(1, 1) 'This is the 'reference' cell - substitute each of the values in the check range for this to test each one
ReDim results(0)
On Error GoTo Err
'''
'Run test on each of the cells in checkRange
'''
For Each subCell In checkRange
    newTest = Replace(formulaTest, topLeft.Address(0, 0), subCell.Address)
    If Count(newTest, "(") < Count(newTest, ")") Then 'when optional parameter is missed out, sometimes you get a ,) and sometimes a ) after formulaTest, so we must check
        newTest = Left(newTest, Len(newTest) - 1)
    End If
    result = (Evaluate(newTest))
skip:
    results(UBound(results)) = result
    ReDim Preserve results(UBound(results) + 1)
Next subCell
'''
'Then use array of Booleans for UDF function
'''
CONCATIF = "test"
Exit Function

Err:
result = False 'if the evaluate results in an error, it means the input was invalid, so probably won't meet the criteria, therefore can be ignored
loopval = loopval + 1
If loopval > checkRange.Cells.Count Then CONCATIF = CVErr(xlErrNA): Exit Function 'exit error loop gracefully if I've missed some edge case
Resume skip

End Function

然后在我的UDF中引用了这个:

Function Count(str As String, chr As String) As Long 'counts the number of instances of a character in a string
     Count = Len(str) - Len(Replace(str, chr, ""))
End Function

1 个答案:

答案 0 :(得分:0)

如果你有一个合适的公式解析器,你可以解决所有这些问题,除了在一个公式中处理多次调用CONCATIF:我不知道找出100%当前CONCATIF实例的方法被召唤。

你周围有各种各样的公式解析器可以适应:从这里开始 http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html