6

对于单元格中的给定 Excel 公式,我希望能够解析公式以获取公式中包含的 Excel 范围引用列表。

例如,如果我有一个带有这个公式的单元格:

= A + 25 + B  

....我希望能够获得公式中包含的 excel 范围数组,因此在这种情况下,它将包含 [A] 和 [B]

“你为什么要这样做”?,我可以听到你问:我
为什么要这样做的一个例子是在公式中查找范围的“标签”......所以,而不是仅仅执行 CTRL+~ 来查看工作表中的公式,我想要以编程方式访问公式中的范围引用的选项,以便在目标范围旁边查找标签。

因此,在上面的示例中,我可以编写如下公式:

=Offset(CellFormulaRanges('TheAddressMyFormulaIsIn',1),0,-1)
=Offset(CellFormulaRanges('TheAddressMyFormulaIsIn',2),0,-1)

...这会给我公式中第一个和第二个范围左侧的标签。

这样做必须调用 Excel 本身中已有的一些功能,因为手写公式解析器是一项复杂的任务:
http ://ewbi.blogs.com/develops/2004/12/excel_formula_p.html

4

3 回答 3

4

感谢@TimWilliams 和@brettdj 为我在之前关于该主题的讨论中指明了正确的方向,我可以自信地说:

不,EXCEL 没有解析方法。

但是,出于我相当小的目的,我想出了一些可行的方法,可以与跨工作表引用一起使用,并且可以从 UDF 中调用。

但是,它非常脆弱,并且有许多完全合法的公式我敢肯定它不会正确处理。

代码是一团糟,可以大大改进,但我只是想把它扔在这里,因为我暂时要转向别的东西......

编辑

还发现了这个,看起来很有趣:
http ://www.dailydoseofexcel.com/archives/2009/12/05/formula-tokenizer/

Public Function CellPrecedents(cell As Range) As Variant()
    Dim resultRanges As New Collection
    If cell.Cells.count <> 1 Then GoTo exit_CellPrecedents
    If cell.HasFormula = False Then GoTo exit_CellPrecedents

    Dim formula As String
    formula = Mid(cell.formula, 2, Len(cell.formula) - 1)

    If IsRange(formula) Then
        resultRanges.Add Range(formula), 1
    Else
        Dim elements() As String
        'Debug.Print formula & " --> "
        formula = Replace(formula, "(", "")
        formula = Replace(formula, ")", "")
        'Debug.Print formula & " --> "
        elements() = SplitMultiDelims(formula, "+-*/\^")
        Dim n As Long, count As Integer
        For n = LBound(elements) To UBound(elements)
            If IsRange(elements(n)) Then
                'ACTUALLY JUST DO A REDIM PRESERVE HERE!!!!
                count = count + 1
                'resultRanges.Add Range(Trim(elements(n)))  '<---  Do **NOT** store as a range, as that gets automatically Eval()'d
                resultRanges.Add Trim(elements(n))
            End If
        Next
    End If

    Dim resultRangeArray() As Variant
    ReDim resultRangeArray(resultRanges.count)
    Dim i As Integer
    For i = 1 To resultRanges.count
        resultRangeArray(i) = CStr(resultRanges(i))  '// have to store as a string so Eval() doesn't get invoked (I think??)
    Next

    CellPrecedents = resultRangeArray

exit_CellPrecedents:
    Exit Function
End Function

Public Function IsRange(var As Variant) As Boolean
    On Error Resume Next
    Dim rng As Range: Set rng = Range(var)
    If err.Number = 0 Then IsRange = True
End Function

(只需谷歌 SplitMultiDelims 即可获得该功能)

于 2012-07-12T18:17:33.383 回答
1

Tbone,另一种选项不是您直接要求的,但可以作为替代解决方案。

与其使用公式来尝试找到相应的标签,不如尝试调整公式以适合您。以下是几个选项,具体取决于您尝试解析的公式是什么。1.如果你的公式是一个查找,你可以偏移到左边看。2. 或者,您可以在两个公式中使用“间接”函数来确保它们引用正确的位置。

于 2015-08-06T18:24:40.097 回答
0

简而言之,我认为您想做 : 的子部分Use VBA to generate code to reproduce basic calculations on an Excel worksheet,并使用函数返回第 n 个 DirectPrecedents 集合元素的地址或名称。

来源:http ://www.vb-helper.com/howto_vba_excel_formulas.html

但是,此用例已被弃用。从 Excel 2007 开始,表格可以提供更好的解决方案。

于 2012-07-04T21:53:39.657 回答