有没有办法根据最终(非公式,仅值)单元格表达复杂的 Excel 公式?

Geo*_*sov 5 worksheet-function microsoft-excel

我有一个非常复杂的 Excel 电子表格(通过多个工作表中的其他公式访问单元格的公式),它最终会使用来自其他几个单元格(参数)的输入来计算单个单元格(输出)。是否有一种自动方式(Excel 宏或独立工具)可以从输出单元格开始并递归展开计算,直到它直接根据参数单元格表达公式?

澄清

在评论中有一个评估公式工具的建议。虽然我找不到如何在 Excel 2008 for Mac 中激活它,但从它的描述来看,它似乎允许用户逐步评估单元格。那不是我需要的。我需要的是一种将给定单元格中可能引用其他包含公式的单元格的公式转换为以最终单元格(包含值但不包含公式的单元格)表示的等效公式的方法。

这是一个简单的例子。让

  • A1 包含 = B1 + C1
  • B1 包含 = B2 * B2
  • C1 包含 = C2 * C2
  • B2 包含 1
  • C2 包含 2

评估公式将允许我逐步完成 的计算A1以获得 的最终值 5。我需要的是一种无需实际评估即可展开A1到公式的工具= B2 * B2 + C2 * C2

tot*_*dli 4

问题

您不能使用评估公式来执行此操作,因为这不是该函数的目的。这就是为什么它被称为评估,它用于评估公式。你想要的是某种拆包。这是一个有点特殊的需求,因此它没有作为 Excel 中的工具实现,但如果您创建一些 Visual Basic 函数/宏,则有一些解决方案。

创建一个 VBA 代码模块(宏),如本教程中所示。

  1. Alt+F11
  2. 单击Module进入Insert.
  3. 粘贴代码。
Function CellFormula(Target As Range) As String
   CellFormula = Target.Formula
End Function
Run Code Online (Sandbox Code Playgroud)

然后在单元格中输入以下内容:=CellFormula(A1)

这将告诉细胞的公式。这段代码的唯一问题是它只适用于一个级别。如果您也想解压包含的单元格公式,那么您需要带有递归的更复杂的代码。

解决方案

这是一个漫长的旅程,但我为您创建了一个 VBA 宏来实现此功能。我并不是说这段代码适用于每个公式,但它适用于大多数/某些公式。另外,我并没有声明此代码将生成与最初输入的代码等效的公式或将给出与原始代码相同的结果。

源代码

Option Explicit

Function isChar(char As String) As Boolean
    Select Case char
        Case "A" To "Z"
            isChar = True
        Case Else
            isChar = False
    End Select
End Function

Function isNumber(char As String, isZero As Boolean) As Boolean
    Select Case char
        Case "0"
            If isZero = True Then
                isNumber = True
            Else
                isNumber = False
            End If
        Case "1" To "9"
            isNumber = True
        Case Else
            isNumber = False
    End Select
End Function

Function CellFormulaExpand(formula As String) As String
    Dim result As String
    Dim previousResult As String
    Dim cell As Range
    Dim stringArray() As String
    Dim arraySize As Integer
    Dim n As Integer
    Dim trimmer As String
    
    Dim c As Integer 'character number
    Dim chr As String 'current character
    Dim tempcell As String 'suspected cell's temporaly result
    Dim state As Integer 'state machine's state:
    Dim stringSize As Integer

    result = formula
    previousResult = result
    state = 0
    stringSize = 0

    For c = 0 To Len(formula) Step 1
        chr = Mid(formula, c + 1, 1)
        Select Case state
            Case 0
                If isChar(chr) Then
                    state = 1
                    tempcell = tempcell & chr
                ElseIf chr = "$" Then
                    state = 5
                    tempcell = tempcell & chr
                Else
                    state = 0
                    tempcell = ""
                End If
            Case 1
                If isNumber(chr, False) Then
                    state = 4
                    tempcell = tempcell & chr
                ElseIf isChar(chr) Then
                    state = 2
                    tempcell = tempcell & chr
                ElseIf chr = "$" Then
                    state = 6
                    tempcell = tempcell & chr
                Else
                    state = 0
                    tempcell = ""
                End If
            Case 2
                If isNumber(chr, False) Then
                    state = 4
                    tempcell = tempcell + chr
                ElseIf isChar(chr) Then
                    state = 3
                    tempcell = tempcell + chr
                ElseIf chr = "$" Then
                    state = 6
                    tempcell = tempcell + chr
                Else
                    state = 0
                    tempcell = ""
                End If
            Case 3
                If isNumber(chr, False) Then
                    state = 4
                    tempcell = tempcell + chr
                ElseIf chr = "$" Then
                    state = 6
                    tempcell = tempcell + chr
                Else
                    state = 0
                    tempcell = ""
                End If
            Case 4
                If isNumber(chr, True) Then
                    state = 4
                    tempcell = tempcell + chr
                Else
                    state = 0
                    stringSize = stringSize + 1
                    ReDim Preserve stringArray(stringSize - 1)
                    stringArray(stringSize - 1) = tempcell
                    tempcell = ""
                End If
            Case 5
                If isChar(chr) Then
                    state = 1
                    tempcell = tempcell + chr
                Else
                    state = 0
                    tempcell = ""
                End If
            Case 6
                If isNumber(chr, False) Then
                    state = 4
                    tempcell = tempcell + chr
                Else
                    state = 0
                    tempcell = ""
                End If
            Case Else
                state = 0
                tempcell = ""
        End Select
    Next c
    If stringSize = 0 Then
        CellFormulaExpand = result
    Else
        arraySize = UBound(stringArray)
        For n = 0 To arraySize Step 1
            Set cell = Range(stringArray(n))
            If Mid(cell.formula, 1, 1) = "=" Then
                trimmer = Mid(cell.formula, 2, Len(cell.formula) - 1)
                If trimmer <> "" Then
                    result = Replace(result, stringArray(n), trimmer)
                End If
            End If
        Next
        If previousResult <> result Then
            result = CellFormulaExpand(result)
        End If
    End If
    CellFormulaExpand = result
End Function

Function CellFormula(rng As Range) As String
    CellFormula = CellFormulaExpand(rng.formula)
End Function
Run Code Online (Sandbox Code Playgroud)

要使其工作,只需创建一个宏(正如我在答案开头所描述的那样)并复制粘贴代码。之后,您可以将其与任何类型的 1x1 单元一=CellFormula(A1)​​起使用。A1

有效案例

我创建了一些示例,以便您可以看到它的实际效果。在本例中,我演示了字符串的使用。你可以看到它运行完美。唯一的小错误是,不知何故,算法将分号更改为逗号。替换它们后(正如我在本示例中所做的那样),您将获得正确的输出。 使用字符串

在这里,您可以看到它如何处理数字。现在,我们面临的第一个问题是算法不关心数学运算顺序,这就是为什么红色数字应该是 10 时却是 6。如果我们将敏感运算(如加法和减法)放在括号中,那么输入的给定公式将给出与底部绿色数字 10 相同的输出。 处理数字

不起作用的情况

这个算法并不完美。我只尝试实现最常见的用途,因此可以通过添加更多处理其他情况(例如范围)的功能来改进它。
正如您在本示例中看到的,我使用SUM()范围作为参数。由于该算法从上到下解密单元格内容,因此它从替换参数开始,SUM()然后再替换任何其他内容。因此,它:留在原来的位置,而它周围的一切都被替换了,所以它附近有新的细胞被替换,谁会改变它的含义。因此输出将是错误的。所以这种情况就只能用这个宏来研究原公式了。 使用范围