【问题标题】:Parsing a function for its arguments解析函数的参数
【发布时间】:2017-04-05 11:28:58
【问题描述】:

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

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

来获得 arg 2

不过有几个问题我想处理

  • 以逗号分隔意味着我的所有论点都不能包含逗号,他们可能不得不这样做
  • 公式可能是嵌套的,例如=SUM(1,IF(CONCATIF(arg1, arg2, arg3)="a",1,0)),所以我不知道我的拆分数组的哪一项是arg2。 (我认为这应该很容易解决:在字符串中找到 CONCATIF 并剪掉开头,数一下它后面的开/关括号直到 open = close,然后剪掉结尾。
  • 参数可能是公式本身; 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

【问题讨论】:

  • 包含您的代码始终是一个好习惯。即使不需要它,也表明您努力使您的问题尽可能做到最好。
  • 发布您的代码。
  • @tompreston 已发布,虽然我不知道它会有多大帮助,因为我已经在问题中概述了我所知道的一切!

标签: vba excel udf


【解决方案1】:

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

您可能会适应各种公式解析器:从这里开始 http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html

【讨论】:

    猜你喜欢
    • 2013-05-11
    • 2011-11-24
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多