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")
尽管它可能很丑陋,但在我看来,它实际上构造得很好; IFS
和 SUMIFS
尽可能避免公式嵌套,所有命名范围存储在表中,在适用的情况下使用辅助列。然而在某些情况下,它 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 公式(公式?)更具可读性的建议往往指向 '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")
尽管它可能很丑陋,但在我看来,它实际上构造得很好; IFS
和 SUMIFS
尽可能避免公式嵌套,所有命名范围存储在表中,在适用的情况下使用辅助列。然而在某些情况下,它 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" 输出方面做得很好。