VBA 使 Excel 公式更具可读性

VBA to make Excel formulae more readable

我浏览了该站点,但有关使 Excel 公式(公式?)更具可读性的建议往往指向 'use named ranges''use helper columns'。我不追求使公式更易于阅读的技术,我想创建一个宏以更易读的方式显示公式。 您可以跳到结尾以获得简短的问题描述。我这样说是因为虽然通常我喜欢解释我的方法,但这次我觉得我的方法可能会分散对问题本质的注意力。另外,我认为这个问题可以在没有所有前面背景的情况下很好地提炼出来

问题背景

我有很多令人讨厌的嵌套式复杂公式,这是我今天写的一个(参见 Excel sample document

或代码:

=IFERROR(IF(Latest[Weekday Num]=5,0,M13+MAX(Table3[Lunchtime],Latest[Lunchtime])-INDEX(Table4[Out],Latest[Weekday Num]))+Table3[Time remaining]-SUMIFS(Table4[Work time],Table4[Weekday Num],">"&Latest[Weekday Num],Table4[Weekday Num],"<5")+Latest[Clocked In]-S13,"Refresh csv")

尽管它可能很丑陋,但在我看来,它实际上构造得很好; IFSSUMIFS 尽可能避免公式嵌套,所有命名范围存储在表中,在适用的情况下使用辅助列。然而在某些情况下,它 returns 是一个错误的结果,并且公式 不是 阅读起来愉快。 (也不是最长的,我编译了好几页a4的代码,虽然那时候我还不能用vba构造辅助列)

我想要一个宏,它采用这个公式并将其拆分为一种分支函数树,其中每个嵌套函数是另一个分支 - 也许将公式的组成部分拆分到工作簿中的单元格中

当前方法

到目前为止,我尝试了以下方法:A 列和 B 列用于将公式拆分为更小的部分。 我将这些部分定义为Excel公式的函数和参数,所以公式IF(A1=1,A2,B1)拆分为IF(A1=1,A2,B1)。我在 B 列中使用以下公式执行此操作:

=LEFT(A2,IFERROR(MAX(1,MIN(IFERROR(FIND("(",A2),LEN(A2)+1),IFERROR(FIND(")",A2),LEN(A2)+1),FIND(",",A2))),LEN(A2)))

同时,A 列查看 B 列找到的最后一个组件,并将其从长公式 (使用 =SUBSTITUTE(A2,B3,"",1) 中删除。 因此,对于 A2 中的原始公式(作为文本),B2 是它的第一个组成部分(例如 IF( 在我的示例中),A3 是 A2 中的公式 minus B2 中的第一个组件。我往下拉迭代。

这为我提供了 B 列每个单元格中的公式组件列表。然后我的宏决定每个组件的级别,并将组件缩进那么多细胞。 level 被定义为在我的代码 中公式 * or 'segment'被关闭。宏注释解释了这一点。

Sub DispFormula()
'takes a split-up formula and indents lines appropriately

Dim CurrLev As Integer, OBrac As Integer, CBrac As Integer
Dim Segment As Range 'each part of the split up formula
LastRow = Sheets("sheet1").Cells(Rows.Count, 2).End(xlUp).Row

Set orange = Range("B2:B" & LastRow) 'all the segments make an orange

CurrLev = 0 'the "level" of the "segment" - it's level is a measure of how many layers deep the formula is nested
            'if(a=1,b,c) is split into 4 components: `if(`, `a=1,`, `b,` & `c)` where `if(` is level 0 and all the other segments are level 1

OBrac = 0 'how many open brackets have happened/ precede a segment of the formula
CBrac = 0 'how many closed brackets have happened
On Error Resume Next
For Each Segment In orange
    If InStr(Segment, "(") <> 0 Then
        OBrac = OBrac + 1
    ElseIf InStr(Segment, ")") <> 0 Then
        CBrac = CBrac + 1
    End If
    Cells(Segment.Row, CurrLev + 3) = Segment 'copies the segment value into a column indented by a number of cells equal to the order of the segment
    CurrLev = OBrac - CBrac 'current level is how many brackets have been opened - how many have been closed,
                            'ie. the number of brackets preceding a segment which are currently open
Next Segment


End Sub

如何改进

这就是我到目前为止的进展。不过,我真正想要的是将缩进树替换为下拉列表树。对于公式 =IF(MAX(arg1,arg2)=1,arg3,MIN(arg1,arg2)) 我想分成几部分:IF(MAX(ARG1,ARG2)=1,ARG3,, MIN(, ARG1, & ARG2)) htn 显示它们。不是这样的:(就像我现在一样)

IF(     
    MAX(    
        ARG1,
        ARG2)
    =1, 
    ARG3,   
    MIN(    
        ARG1,
        ARG2))

但像这样:(或类似的)

IF(◀

当你点击 时会变成这样:

IF(▼
    MAX(◀   
    =1, 
    ARG3,   
    MIN(◀

然后将 Min 扩展为

IF(▼
    MAX(◀   
    =1, 
    ARG3,   
    MIN(▼
        ARG1,
        ARG2))

缩短问题描述


总结一下:

  • 我在Excel中有一个公式; Excel 中的公式具有一般形式 FUNCTION(argument1, arg2, arg3...)
  • 每个参数可以是简单的(常量、文本字符串、单元格引用)或复杂的(另一个具有自己的函数和参数的公式)
  • 我想要一个宏,它接受一个输入公式,并创建某种形式的用户界面(无论是在我的示例中专门定位的单元格,还是其他一些方法)以像时尚一样在树中显示函数
  • 这意味着在 UI 的第一层,我显示函数,第 2 层有函数的参数,如果参数很复杂,它们将有更多的子层
  • 要访问子层,可以使用下拉箭头或其他方式展开每个函数以显示其参数(其下方的 'layer')。就像 Reddit post 一样,您可以在其中单击 [+] 以深入一层。

我使用这个网站来处理长公式,它对我帮助很大。

它没有您提到的 UI 组件,但它在 "beautifying" 输出方面做得很好。

Excel Formula Beautifier