在VBA中打高尔夫球的技巧


16

类似于thisthisthis问题...

您有哪些打高尔夫球的一般秘诀VBA?我正在寻找可以应用于编码高尔夫问题的想法,这些想法至少在某些方面是特定的VBA(例如,“删除评论”不是答案)。请为每个答案发布一个提示。

当我使用其他语言时,我的能力最强VBA,而且VBA在这个网站上我看不到有很多高尔夫球手在使用。


已根据政策转换为社区Wiki。
dmckee ---前主持人小猫,2012年

抱歉,这对我来说不是自动的!
加菲2012年

没事。实际上,他们已经拥有向用户发送CW问题的权力(我认为您仍然可以回答)。您可以标记主持人的注意力,但是几乎不需要CodeGolf进行的活动。
dmckee ---前主持人小猫,2012年

2
VBA是一种相对冗长的语言,几乎没有语法快捷方式。如果您想获得最高分,VBA可能不是一个好选择。如果您想磨练自己的技能,可以使用更多功能。
骆马先生2012年

2
@GigaWatt磨练我的技能。实际上,自从面对各种挑战以来,我已经学到了一些使用VBA的新技巧!我不希望通过VBA 赢得任何真正的 代码高尔夫挑战,但这是一个好习惯。:-)
加菲2012年

Answers:


8

ByRef调用潜艇时利用默认设置

有时可以使用Sub呼叫代替a Function来保存一些其他字符...

这(87个字符)

Sub a()
b = 0
Do Until b = 5
b = c(b)
Loop
End Sub
Function c(d)
c = d + 1
End Function

可以重新制作为(73个字符):

Sub a()
b = 0
Do Until b = 5
c b
Loop
End Sub
Sub c(d)
d = d + 1
End Sub

请注意,尽管您永远不会重新分配的值,但这不会永远循环b

上面的代码不使用Function调用,而是利用了调用的ByRef“按引用”功能Sub。这意味着传递的参数与调用函数中的变量相同(而不是ByVal传递“按值”,它是一个副本)。对传递的变量的任何修改都将转换回调用函数。

默认情况下,将所有参数都用作ByRef,因此不需要用完字符来定义它。

上面的示例可能无法完全为您翻译,具体取决于函数的返回值。(即返回与传递的数据类型不同的数据类型),但这也允许在仍修改原始变量的同时获得返回值的可能性。

例如:

Sub a()
b = 0
Debug.Print c(b) ' This will print 0, and b will equal 1.'
End Sub
Function c(d)
c = d
d = d + 1
End Function

7

在立即窗口中编写并运行VBA代码

立即窗口评估任何有效的VBA可执行语句。就像在代码编辑器中一样,只需在立即窗口中输入一条语句。它可以快速执行VBA代码,并且可以保存许多其他字符,因为:

  1. 在语句的开头放置问号(?)会告诉“即时窗口”显示代码结果。

enter image description here

  1. 您无需在代码中使用Sub和End Sub。

enter image description here


这是“即时窗口”中以标签回答PPCG帖子的VBA代码示例:不带A的字母A

?Chr(88-23);

乔凡回答。


图片来源: Excel Campus


1
那使用REPL环境吗?这意味着它只是片段,而不是程序或功能
Caird coinheringaahing

我认为要添加的另一个示例可能是您还可以内联创建变量。例如,a="value":?a首先设置的值a,然后打印它。
Greedo

6

循环之前的条件检查

与循环结合使用时,某些条件检查是多余的。例如,For如果起始条件超出运行条件的范围,则不会处理循环。

换句话说,这(49个字符):

If B > 0 Then
For C = A To A + B
'...
Next
End If

可以变成这个(24个字符):

For C = A To A + B ' if B is 0 or less, then the code continues past Next, unabated.
'...
Next

底部的注释不正确。如果B = 0,则将进入循环。 pastebin.com/97MBB7hq
QHarr,

5

变量声明

在大多数情况下,在VBA中,您Option Explicit可以省去(无论如何,默认情况下通常都会省略)并跳过Dim许多变量。

这样做,(96个字符):

Option Explicit

Sub Test()
Dim S As String
Dim S2 As String
S = "Test"
S2 = S
MsgBox S2
End Sub

变成这个(46个字符):

Sub Test()
S = "Test"
S2 = S
MsgBox S2
End Sub

如果需要使用某些对象(例如,数组),则可能仍需要Dim该变量。


请稍等,您接受了自己对问题的回答。不酷,老兄
泰勒·斯科特

1
@TaylorScott这是一个Wiki帖子-没有要点,在这种情况下,没有一个最佳答案。:)我接受大约5年前的答案,以避免在我的问题列表中出现标记。
加菲

1
@TaylorScott还可以,如果您接受自己的答案,则不会获得+15或+2(接受)
caird coinheringaahing

5

Evaluate()[]

如前所述,使用方括号[A1]符号可以减少硬编码的范围调用。但是,它不仅具有更多用途。

根据MSDN文档,该Application.Evaluate()方法采用单个参数,即NameMicrosoft Excel的命名约定定义的a 。

NB [string]是简写形式Evaluate("string")(请注意""表示字符串数据类型的语音标记),尽管最后有一些重要的区别。

那么,就使用而言,这意味着什么呢?

从本质上讲,它[some cell formula here]代表一个Excel工作表中的单元格,您可以将几乎任何内容放入其中,并从中获得与普通单元格一样的任何内容

进来什么

总结,带有例子

  • A1样式的引用。所有参考均被视为绝对参考。
    • [B7] 返回对该单元格的引用
    • 由于引用是绝对的,因此?[B7].Address返回"B$7$"
  • 范围可以将范围,相交和并集运算符(分别为冒号,空格和逗号)与引用一起使用。
    • [A1:B5]返回对A1:B5(Range)的范围引用
    • [A1:B5 A3:D7]返回对A3:B5(相交)的范围引用
    • [A1:B5,C1:D5]返回A1:D5(技术上A1:B5,C1:D5)(Union)的范围引用
  • 定义名称
    • 用户定义,例如[myRange]参考A1:G5
    • 自动,就像表名一样[Table1](可能对codegolf没什么用)
    • 您可以在[Formulas]> [Name Manager]菜单中找到其他任何内容
  • 公式
    • 非常有用 ; 可以进入单元格的任何公式都可以进入Evaluate()[]
    • [SUM(1,A1:B5,myRange)]返回范围myRange范围内的值的算术总和,此处引用的是工作簿名称,而不是VBA变量
    • [IF(A1=1,"true","false")](比vba短1个字节Iif([A1]=1,"true","false")
    • 数组公式[CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]-将长度大于2的范围内的所有字符串以空格连接
  • 外部参考
    • 您可以使用!运算符来引用一个单元格或另一个工作簿中定义的名称
    • [[BOOK1]Sheet1!A1]在BOOK1中返回对A1的范围引用,或者['[MY WORKBOOK.XLSM]Sheet1!'A1]MY WORKBOOK
    • 请注意'名称中带有空格的for工作簿,以及默认命名工作簿(BOOK+n)缺少扩展名
  • 图表对象(请参阅MSDN文章)

注意:我在SO上询问了有关此信息的问题,因此请看那里以获得更好的解释

结果如何

与输入内容类似,输出内容包括工作表单元格可以返回的所有内容。这些是标准Excel数据类型(及其等效的VBA):

  • 逻辑(Boolean
  • 文字(String
  • 数值(Double
  • 错误(Variant/Error)(这些是不间断的错误,即它们不停止代码执行,?[1/0]可以正常执行)

但是有些事情可以返回,而单元格则不能:

  • 范围参考(Range)(请参阅以上部分)
  • 数组(Variant()

数组

如图所示,[]可用于评估返回标准Excel数据类型之一的数组公式;例如[CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]返回Text。但是Evaluate也可以返回Variant类型的数组。这些可以是

硬编码:

[{1,2;3,4}]-输出2D数组:,是列分隔符,用于;分隔行。可以输出一维数组

数组公式:

[ROW(A1:A5)]-输出2D数组{1,2,3,4,5},即(2,1)是第二项(但某些函数输出1D数组)

  • 无论出于何种原因,某些函数默认情况下都不返回数组

[LEN(A1:A5)] 仅输出范围的第一个单元格中的文本长度

  • 但是这些可以被强制给出数组

Split([CONCAT(" "&LEN(A1:A5))]) 给出一维数组0到5,其中第一项为空

[INDEX(LEN(A1:A5),)]是另一种解决方法,本质上,您必须使用数组处理函数来获得所需的数组返回行为,类似于添加无意义的操作RAND()以使工作表公式易变。

  • 我问了一个有关SO问题,以尝试获取一些更好的信息,如果找到它们,请进行编辑/评论并提供更好的选择

Evaluate()[]

Evaluate()和之间存在一些差异[],需要注意

  1. 字符串与硬编码
    • 也许最重要的区别是,Evaluate接受字符串输入,其中[]需要硬编码输入
    • 这意味着你的代码可以建立与变量的字符串如Evaluate("SUM(B1,1,"&v &",2)")将总结[B1]12和可变v
  2. 数组

    返回数组时,只能将Evaluate与数组索引一起使用,因此

    v=Evaluate("ROW(A1:A5)")(1,1) ''#29 bytes

    相当于

    i=[ROW(A1:A5)]:v=i(1,1) ''#23 bytes

抱歉,对于庞然大物,如果有人觉得可以使区域更简洁/如果您有添加提示,请放心。另外,尽管我对此进行了研究,但是通过在VBA中进行实验发现了相当一部分,因此,如果您发现感觉上有失误,​​请不要犹豫地进行评论/编辑!
Greedo

1
实际上,关于数组的最后一部分有点过头-可以在即时窗口中使用i=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott

@TaylorScott因此,您可以,我完全不知道您可以在尚未定义的变量中设置/保存值,但是我想那是因为我仍在使用“即时”窗口1-liners。已进行相应的更新
Greedo '17

与Match搭配使用吗?我尝试过,但是它总是返回错误。不过,我正在传递数组而不是范围。
seadoggie01

5

合并Next报表

Next:Next:Next

可能会浓缩为

Next k,j,i

其中对于迭代器For环路ij以及k-按照这个顺序。

例如以下(69字节)

For i=0To[A1]
For j=0To[B1]
For k=0To[C1]
Debug.?i;j;k
Next
Next
Next

可以压缩到65字节

For i=0To[A1]
For j=0To[B1]
For k=0To[C1]
Debug.?i;j;k
Next k,j,i

至于这如何影响格式和缩进,我认为处理此问题的最佳方法是将下一条语句与最外层的for语句对齐。例如。

For i=0To[A1]
    For j=0To[B1]
        For k=0To[C1]
            Debug.?i;j;k
Next k,j,i

4

减少If陈述

使用条件If ... Then ... Else检查分配变量时,可以End If通过将整个检查放在一行上来消除,从而减少使用的代码量。

例如,这(37个字符):

If a < b Then
c = b
Else
c = a
End If

可以减少到30个字符

If a < b Then c = b Else c = a

如果您有多个嵌套条件,则也可以通过以下方式将它们最小化:

If a Then If b Then If c Then Z:If d Then Y:If e Then X Else W Else V:If f Then U 'Look ma! No "End If"!

注意,:允许您在一个If块中添加多个行/命令。

在这种简单情况下,通常也可以Else通过在If检查前将变量设置为25个字符来删除:

c = a
If a < b Then c = b

更好的是,可以使用IIf()函数(20个字符)将以上内容简化为:

c = IIf(a < b, b, a)

3

减少Range("A1")和点赞电话

Range("A1").Value(17字节)和较简单的Range("A1")(11字节)可以减少到[A1](4字节)


2
或通常来说,在VBA中使用[]replace Evaluate()不仅比范围调用更通用。例如,您可以将其替换WorksheetFunction.FuncName(args)为just [FuncName(args)],例如?[SUMPRODUCT({1,3,5},{2,7,-1})]或非常有用的[MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Greedo,这是一个非常重要的功能,我不知道您应该将此添加为它自己的答案。
泰勒·斯科特

1
当然,我会尽快写点东西。是的,Evaluate("str")或者[str]在VBA中速记功能非常强大,我最近才发现它,而且我猜想它对打高尔夫球也很有用!
Greedo

非常有用,足够使我回头查看答案是否可以因此而删除我的字节数
Taylor Scott

3

删除空间

VBA会自动格式化以增加很多实际不需要的间距。在meta上有一个答案,这对我来说很有意义,为什么我们可以取消通过自动格式化添加的字节。不过,重要的是要始终确保您没有卸下太多东西。例如,这是我的答案仅通过删除空格就减少了近22%:

原始版本:(188字节)

Sub g(n)
For i = 0 To 1
For x = -3 To 3 Step 0.05
y = n ^ x * Cos(Atn(1) * 4 * x)
If y < m Then m = y
If i = 1 Then Cells(500 * (1 - y / m) + 1, (x + 3) * 100 + 1) = "#"
Next
Next
End Sub

精简版:(146字节)

Sub g(n)
For i=0To 1
For x=-3To 3Step 0.05
y=n^x*Cos(Atn(1)*4*x)
If y<m Then m=y
If i=1Then Cells(500*(1-y/m)+1,(x+3)*100+1)="#"
Next
Next
End Sub

如果将简化版本复制/粘贴到VBA中,它将自动扩展为原始版本。您可以在删除空格有效的地方玩耍。到目前为止,我发现的所有命令似乎都遵循以下模式:期望VBA出现某个命令,因为没有它,它不是有效的代码。到目前为止,我发现了一些:

  • 在任何数学运算之前和之后: +-=/*^
  • 之前ToStepFor声明中:For x=-3To 3Step 0.05
  • 实际上,在任何保留字(To&Then等),如果它由一个立即诸如数字前缀,)?%,等。
  • 之后 &组合字符串之后:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • 函数调用后: If s=StrReverse(s)Then
  • 在函数调用中: Replace(Space(28)," ",0)

通过自动格式化添加非空格字符的规则是什么?我所看到的?vs之类的东西Print是可以接受的,但是像&在一个变量之后立即Debug.?a&"z"给出类型声明,例如gives Debug.Print a&; "z";添加的字符对于代码的运行至关重要-是否仍然允许这样做?
Greedo

2
@Greedo我以meta答案描述它的方式看到它:如果可以将其复制/粘贴到编辑器中,并且代码将运行,就可以了。IE,如果在粘贴代码时VBA自动将字符添加回去,那么就可以了。
Engineer Toast

1
@EngineerToast你其实可以放下一个多字节关闭您的例子:If i=1 Then 可能会If i=1Then ,因为作为一般规则如下文字保留字,是一个数字,)?%,...等,并不需要由分离空间
泰勒·斯科特

1
@EngineerToast,您还可以从第三个项目符号处删除一个字节,因为您可以删除)(或任何其他非数字文字)和&
Taylor Scott Scott

3

准备像素艺术

像素艺术是迄今为止Excel最强大的领域之一,因为不需要构造画布,因为它已经为您提供了-您需要做的只是做一些小调整

1)使单元格方形

Cells.RowHeight=48

或者,也可以再增加1个字节,但使用起来要容易得多

Cells.ColumnWidth=2

2)上色所需范围

任何Range物体都可以通过调用来着色

`MyRangeObj`.Interior.Color=`ColorValue`

注意:这可以并且应该与该Wiki上提到的其他技巧结合使用,例如使用[]符号(例如[A1:R5,D6])引用范围而不是使用a Cells(r,c)或aRange(cellAddress)调用。此外,如该Wiki所述,此值可以与负色值组合以降低颜色参考的大小

快速参考

范围参考

细胞 A1可以通过以下任何方式引用

Range("A1")
Cells(1,1)
[A1]

和范围 A1:D4可以通过以下任何一种方式引用

Range("A1:D4")
Range("A1").Resize(4,4)
Cells(1,1).Resize(4,4)
[A1].Resize(4,4,)
[A1:D4]

颜色参考

Black  0
White  -1
Red    255
Aqua   -256

3

简化内置功能

当经常使用某些功能时,请将它们重新分配给用户定义的功能。

以下代码(127个字符)可以减少为:

Sub q()
w = 0
x = 1
y = 2
z = 3
a = Format(w, "0.0%")
b = Format(x, "0.0%")
c = Format(y, "0.0%")
d = Format(z, "0.0%")
End Sub

至(124个字符):

Sub q()
w = 0
x = 1
y = 2
z = 3
a = f(w)
b = f(x)
c = f(y)
d = f(z)
End Sub
Function f(g)
f = Format(g, "0.0%")
End Function

结合使用ByRef技巧,您可以保存更多字符(最多114个):

Sub q()
w = 0
x = 1
y = 2
z = 3
a = f(w)
b = f(x)
c = f(y)
d = f(z)
End Sub
Sub f(g)
g = Format(g, "0.0%")
End Sub

明智地执行此操作,因为VBA会占用很多字符来定义Function。所述第二码块实际上是比所述第一与较大的任何数量少的Format()呼叫。


2
在上一个中,您不需要分配呼叫,这意味着a = f(w)可以简化为f w
Taylor Scott

3

STDIN和STDOUT

通过输入变量输入Sub例程和Functions

Public Sub A(ByRef B as String)

可能减少到

Sub a(b$) 

PublicByRef电话是VBA,因而隐含的默认值,并可能(几乎)总是被丢弃。

类型文字$强制b为类型String

其他类型文字

  • !
  • @ 货币
  • #
  • % 整数
  • $
  • &
  • ^ LongLong(仅64位)

此外,通常可以将输入变量保留为默认类型,Variant并且不处理任何基于类型的错误。例如。Sub E(F)其中F应该是类型Boolean[](将传递给例程,如E Array(True, False, False)

通过输入到Sub例程和立即窗口函数Cells

VBA没有功能齐全的控制台,因此没有任何官方的 STDIN,因此允许一些通过传递输入。

在excel中,通常接受从一个单元格或一系列单元格中获取输入,这可以像

s=[A1]

会隐式地将其.value从单元格中放入[A1](也可以称为cells(1,1)range("A1")

示例问题:在消息框中显示输入

通过子程序 Sub A:msgbox[A1]:End Sub

通过即时窗口功能 msgbox[A1]

通过条件编译参数输入

VBA项目支持从命令行或通过VBAProject属性获取参数(通过项目浏览器查看-> [您的VBA项目]-(右键单击)-> VBAProject属性->条件编译参数)

这对于错误代码挑战非常有用

给定条件编译参数n=[some_value],这允许基于的值执行将生成错误代码的代码n。请注意,这需要为n=VBAProject属性窗格的条件编译参数部分中的代码增加2个字节。

范例程式码

...
#If n=3 then
return ''  Produces error code '3', Return without GoSub
#ElseIf n=20 then
resume ''  Produces error code '20', Resume without Error
#EndIf
...

通过功能值输出

在这里不必多说,下面引用的一般形式要尽可能紧凑。

Public Function A(b)
    ...
    A=C
End Function

注意:绝大多数情况下,将方法转换为子例程并输出到VBE立即窗口的字节更多(请参见下文)

Sub例程输出Function通过VBE Instants窗口 s

输出到VBE立即窗口(又称VBE调试窗口)是VBA应对基于文本的挑战的一种常见输出方法,但是,重要的是要记住,Debug.Print "Text"通话可能会打高尔夫球。

Debug.Print "Text"

在功能上与

Debug.?"Text"

作为?自动格式化为Print

从输出 Sub通过其他方法例程和VBE Instants Window函数

极少数情况下,当情况恰到好处时,您可以从VBA可用的一些更简单的输入中获取输入,例如字体大小调整器,字体选择器和缩放。(例如,模拟Word字体大小选择器


2

格式化快速说明

因为StackExchange使用MarkdownPrettify.js,因此可以在编码答案中添加语言标记,这通常会使它们看起来更加专业。尽管我不能保证这会使您在VBA中打高尔夫球更好,但我可以保证它会使您看起来像自己。

添加以下任一标志将进行转换

Public Sub a(ByRef b As Integer) ' this is a comment

Public Sub a(ByRef b As Integer) ' this is a comment

VBA语言标签

<!-- language: lang-vb -->

<!-- language-all: lang-vb -->

注意:后者转换答案中的所有代码段,而前者仅转换紧随其后的代码段


lang-vb嗯?-奇怪的是,这种格式比lang-vbavba答案的格式更好。
Greedo

1
@Greedo,这是因为虽然lang-vba将提供突出显示,但实际上它只是默认的突出显示。显然,VBA实际上尚未在Prettify.js中实现,因此我们必须坚持VB突出显示
Taylor Scott

2

多次If .. Then检查

正如在其他语言,多If检查通常可以组合成单个线,从而允许使用的And/ Or(即&&/ ||C和其他),其在VBA取代了一个Then和一个End If

例如,使用嵌套条件(93个字符):

'There are MUCH easier ways to do this check (i.e. a = d).
'This is just for the sake of example.
If a = b Then
    If b = c Then
        If c = d Then
            MsgBox "a is equal to d"
        End If
    End If
End If

可以变成(69个字符):

If a = b And b = c And c = d Then
    MsgBox "a is equal to d"
End If

这也适用于非嵌套条件条件。

考虑(84个字符):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

可以变成(51个字符):

If a = b Or c = b Then            
    d = 0
End If

1
在If-then语句中,如果您在单行中编写代码,则“ End-if”部分是可选的。
Stupid_Intern '17

@newguy正确。另请参见此
加菲(Gaffi)

上面的陈述可以进一步d=iif(a=b or c=b,0,d)
泰勒·斯科特

2

结尾 For循环

使用For循环时,Next一行不需要变量名(尽管最好在常规编码中使用)。

因此,

For Variable = 1 to 100
    'Do stuff
Next Variable

可以缩短为:

For Variable = 1 to 100
    'Do stuff
Next

(节省的费用取决于您的变量名,不过,如果您打高尔夫球,那大概只有1个字符+ 1个空格。)


1
2个字符,别忘了数空格!
2013年

我碰巧几乎从不识别变量,即使在普通代码中也是如此!
dnep

2

将字符串拆分为字符数组

有时将字符串分割成单个字符可能很有用,但是在VBA中手动执行此操作可能需要一些代码。

ReDim a(1 To Len(s))
' ReDim because Dim can't accept non-Const values (Len(s))
For i = 1 To Len(s)
    a(i) = Mid(s, i, 1)
Next

相反,您可以使用单行,相对较少的功能链来完成工作:

a = Split(StrConv(s, 64), Chr(0))

这会将您的字符串分配sVariantarray a。但是要小心,因为数组中的最后一项将是一个空字符串(""),需要适当处理。

其工作方式如下:该StrConv函数将将a转换为String您指定的另一种格式。在这种情况下,64 = vbUnicode,因此它将转换为unicode格式。处理简单的ASCII字符串时,结果是""在每个字符后插入一个空字符(不是空字符串)。

接下来,SplitString使用空字符将结果转换为数组Chr(0)作为分隔符。

重要的是要注意,Chr(0)它与空字符串不同"",并且使用Spliton ""不会返回您可能期望的数组。这同样适用vbNullString(但如果您打高尔夫球,那为什么首先要使用这样的冗长常量?)。


您应该提到,结果数组的末尾还有一个空字符串。
2013年

@霍华德是的,我应该。当我输入此内容时,它在我的脑海中,一定让我无所适从。
加菲2013年

2

使用With(有时!请参见脚注)

With如果重复使用某些对象,则使用该语句可以大大减少代码大小。

即这(80个字符):

x = foo.bar.object.a.value
y = foo.bar.object.b.value
z = foo.bar.object.c.value

可以编码为(79个字符):

With foo.bar.object
    x = .a.value
    y = .b.value
    z = .c.value
End With

以上甚至不是最好的情况。如果对进行任何使用Application,例如Excel.Application从Access中使用,则改进将更为显着。


*视情况而定,With可能比这更有效(64个字符):

Set i = foo.bar.object
x = i.a.value
y = i.b.value
z = i.c.value

2

无限循环

考虑更换

Do While a<b
'...
Loop

要么

Do Until a=b
'...
Loop

具有过时但较低的字节数

While a<b
'...
Wend

如果您需要退出SubFunction过早退出,则可以使用Exit ...

For i=1To 1000
    If i=50 Then Exit Sub
Next

考虑 End

For i=1To 1E3
    If i=50 Then End
Next

请注意,这会End暂停所有代码执行并清除所有全局变量,因此请明智使用


您应该考虑重写最后一部分(ForEnd)以反映该案件100将永远不会得到解决,并添加了一个不必要的字节
Taylor Scott

另外,尽管这很容易理解,但您可以考虑删除空格以更好地显示这些方法的可能优势(总是将VBA中的自动格式设置用于代码golfing总是很好的)
Taylor Scott

2

使用Spc(n)结束Space(n)[Rept(" ",n)]String(n," ")

尝试插入多个长度的空格时n,请使用

Spc(n)              ''  6  bytes

过度

B1=n:[Rept(" ",B1)] ''  19 bytes
String(n," ")       ''  13 bytes
Space(n)            ''  8  bytes

注意:我不确定为什么,但是您似乎无法将的输出赋值给Spc(n)变量,而必须直接将其打印-因此在某些情况下,Space(n)这仍然是最好的方法。


2

减少Debug.PrintPrint通话

Debug.Print [some value] 

(12字节;请注意尾随空格)可以减少为

Debug.?[some value]

(7字节;请注意缺少尾随空间)。

同样,

Print 

(6字节)可减少为

?

(1字节)。

此外,当在匿名VBE立即窗口函数的上下文中操作时,该Debug语句可以完全删除,而?可以假定通过打印到VBE立即窗口通过是STDIN / STDOUT。

特殊的角色

打印字符串时,也可以使用特殊字符代替&。这些允许在打印的内容或空格删除中使用其他格式

连接变量字符串,而不是

Debug.Print s1 &s2

您可以使用分号 ;

Debug.?s1;s2

只要没有歧义,此分号是连续字符串的默认行为,因此它们是有效的:

Debug.?s1"a"
Debug.?"a"s1

但不是

Debug.?s1s2 'as this could be interpreted as a variable named "s1s2", not 2 variables
            'use Debug.?s1 s2 instead (or s1;s2)
Debug.?"a""b" 'this prints a"b, so insert a space or ; for ab

注意a; 在行的末尾禁止换行,因为默认情况下,每次打印后都会添加换行。VBA代码返回的字节计数尚有争议

要与制表符连接,请使用逗号,(实际上是14个空格,但根据)

Debug.?s1,s2 'returns "s1              s2"

最后,您可以使用类型声明而不是;来连接字符串,每个声明对格式都有轻微的影响。对于以下所有a = 3.14159内容,第一行

Debug.?a&"is pi" -> " 3 is pi" 'dims a as long, adds leading and trailing space to a
Debug.?a!"is pi" -> " 3.14159 is pi" 'dims a as single, adds leading and trailing space
Debug.?a$"is pi" -> "3.14159is pi" 'dims a as string, no spaces added

2

使用辅助SubPrint

如果代码需要使用六个以上的 Debug.?语句,则可以通过替换所有Debug来减少字节数。行与对Sub的调用(如下所示)。要打印空白行,p ""由于需要参数,因此需要调用。

Sub p(m)
Debug.?m
End Sub

1
要仅使用新行p""或您可以将其终止,请打印新行p"。但是,在绝大多数情况下,使用字符串变量并且仅在最后打印字符串变量更有意义。
泰勒·斯科特

1

使用Array() Choose()代替SelectIf...Then

当基于另一个变量的值分配变量时,有意义的是使用If...Then检查写出步骤,如下所示:

If a = 1 Then
b = "a"
ElseIf a = 2 Then
b = "c"
'...
End If

但是,如果要检查的变量不止一个或两个,那么这可能会占用大量代码空间(无论如何,通常还有更好的方法来执行此操作)。

相反,该Select Case语句通过将所有内容封装在一个块中来帮助减少检查的大小,如下所示:

Select Case a
Case 1:
b = "a"
Case 2:
b = "c"
'...
End Select

这样可以减少代码的数量,但是对于像这样的非常简单的情况,有一个甚至更有效的方法:Choose()该函数将基于传递给它的值从列表中选择一个值。

b = Choose(a,"a","c",...)

选择的选项(a在这种情况下)是作为第一个参数传递的整数值。所有后续参数都是可以选择的值(像大多数VBA一样,为1索引)。值可以是任何数据类型,只要它与所设置的变量匹配即可(即对象没有Set关键字就无法工作),甚至可以是表达式或函数。

b = Choose(a, 5 + 4, String(7,"?"))

另一个选择是使用该Array函数在保存另一个字符的同时获得相同的效果:

b = Array(5 + 4, String(7,"?"))(a)

高尔夫的一个有趣且可能非常有益的用途是将其与一个IIf()或另一个结合使用Choose()A1=IIf(a=Choose(b,c,d,e),Choose(Choose(f,g,h,i),j,k,l),Choose(IIf(m=n,Choose(p,q,r,s),IIf(t=u,v,w)),x,y,z))
加菲(Gaffi)2012年

1

位移的RGB值

由于Excel处理颜色的方式(无符号的6个字符的十六进制整数),您可以使用带负号的整数,其中excel将仅使用正确的6个字节来分配颜色值

这有点令人困惑,因此下面提供了一些示例

假设您要使用白色,该颜色存储为

rgbWhite

相当于

&HFFFFFF ''#value: 16777215

若要向下推算,我们需要做的是找到一个以终止的十六进制值,FFFFFF并且由于in的负十六进制值必须采用从()到()倒数的FFFFXXXXXX(这样X的有效十六进制)格式。FFFFFFFFFF-1FFFF000001-16777215))。

知道了这一点,我们可以将公式概括为

Let Negative_Color_Value = -rgbWhite + Positive_Color_Value - 1
                         = -16777215 + Positive_Color_Value - 1
                         = -16777216 + Positive_Color_Value

使用此功能,可以进行一些有用的转换

rgbWhite = &HFFFFFF = -1 
rgbAqua  = &HFFFF00 = -256
16747627 = &HFF8C6B = -29589

很高兴知道那里发生了什么,我只是在那个问题中偶然发现了它-但是这个清晰的解释准确地显示了它是如何工作的。要记住的另一件事是,可以使用数学运算符来减少某些关键色。rgbWhite= 2^24-1尽管如果您错过-1可能会进一步减少到大约-1,则可能会进一步减少
Greedo

1
实际上,这里有一个颜色及其数学表示形式的列表,这些颜色比正或负十进制版本要短:&000080: 2^7, &000100: 2^8, &000200: 2^9, &000400: 2^10, &000800: 2^11, &001000: 2^12, &002000: 2^13, &004000: 2^14, &008000: 2^15, &010000: 2^16, &01FFFF: 2^17-1, &020000: 2^17, &03FFFF: 2^18-1, &040000: 2^18, &07FFFF: 2^19-1, &080000: 2^19, &0FFFFF: 2^20-1, &100000: 2^20, &1FFFFF: 2^21-1, &3FFFFF: 2^22-1, &400000: 2^22, &7FFFFF: 2^23-1 nb不一定完整,但我认为我做得相当透彻
Greedo

1

"打印到即时窗口时省略终端

给定下面的功能,该功能将在调试窗口中使用

h="Hello":?h", World!"

终端"可能会丢失-1字节,未关闭字符串,程序应执行相同的操作,而不会出现错误

h="Hello":?h", World!

比这更令人惊讶的是,这可以在完全定义的子例程中完成。

Sub a
h="Hello":Debug.?h", World!
End Sub

上面的子例程按预期运行,并自动格式化为

Sub a()
h = "Hello": Debug.Print h; ", World!"
End Sub

1

在条件中使用Truthy和Falsey变量

有时也被称为隐式类型转换-直接使用一个号码类型If[IF(...)]IIf(...)语句,通过使用数量绝对可以为您节省一些字节的truthy和falsey性质。

在VBA中,任何非零的数字类型变量都被认为是真实的(因此,零0是唯一的虚假值),因此

If B <> 0 Then 
    Let C = B
Else 
    Let C = D
End If 

可能凝结为

If B Then C=B Else C=D

并进一步

C=IIf(B,B,D)

1

地址表按名称

而不是WorkSheet通过调用来寻址对象

Application.ActiveSheet
''  Or 
ActiveSheet   

一个可以使用

Sheets(n)  ''  Where `n` is an integer
''  Or 
[Sheet1]

或更优选地,可以直接访问该对象并使用

Sheet1

1

LongLong64位VBA中的幂和s

求幂的一般形式

A to the power of B

可以在VBA中表示为

A^B 

但是,只有在Office的32位安装中,在 Office的64位安装中,您可以无错误地表示的最短方法是

A ^B

这是因为在64位版本的VBA中^,它既用作指数文字,又用作LongLong类型声明字符。这意味着可能会出现一些看起来很奇怪但有效的语法,例如

a^=2^^63^-1^

分配变量a以保存a的最大值Longlong


1

将字节数组压缩为字符串

对于需要解决方案来保存恒定数据的挑战,将数据压缩为单个字符串然后在字符串中进行迭代以获取数据可能是有用的。

在VBA中,任何字节值都可以直接转换为

Chr(byteVal)

并且a longintegervalue可以转换为两个字符

Chr(longVal / 256) & Chr(longVal Mod 256)

因此,对于byte数组,压缩算法看起来像

For Each Var In bytes
    Select Case Var
        Case Is = Asc(vbNullChar)
            outstr$ = outstr$ & """+chr(0)+"""
        Case Is = Asc(vbTab)
            outstr$ = outstr$ & """+vbTab+"""
        Case Is = Asc("""")
            outstr$ = outstr$ & """"""
        Case Is = Asc(vbLf)
            outstr$ = outstr$ & """+vbLf+"""
        Case Is = Asc(vbCr)
            outstr$ = outstr$ & """+vbCr+"""
        Case Else
            outstr$ = outstr$ & Chr$(Var)
    End Select
Next
Debug.Print "t="""; outstr$

注意该Select Case部分是由于字符而实现的,这些字符可能不会作为文字存储在字符串中。

从结果字符串中,看起来像

t="5¼-™):ó™ˆ"+vbTab+"»‘v¶<®Xn³"+Chr(0)+"~ίšÐ‘š;$ÔÝ•óŽ¡¡EˆõW'«¡*{ú{Óx.OÒ/R)°@¯ˆ”'®ïQ*<¹çu¶àªp~ÅP>‹:<­«a°;!¾y­›/,”Ì#¥œ5*B)·7    

然后可以使用AscMid函数提取数据,例如

i=Asc(Mid(t,n+1))

1

使用不正确的常数

在某些情况下,VBA允许在需要常量值的表达式中使用未列出或不适当的常量。这些通常是遗留值,并且长度短于适当值。

例如,当让rng.HorizantalAlignment属性保留值时,可以使用以下值 。

ImproperProperGeneral ConstantxlHAlign  Constant11xlGeneralxlHAlignGeneral24131xlLeftxlHAlignLeft34108xlCenterxlHAlignCenter44152xlRightxlHAlignRight55xlFillxlHAlignFill64130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection84117xlDistributedxlHAlignDistributed

This means, for example that setting a cell to having its text centered with

rng.HorizantalAlignment=-4108

may be shortened down to

rng.HorizantalAlignment=3

by replacing the improper constant value 3 for the proper value -4108. Note that if you fetch the rng.HorizantalAlignment property value, it will return the proper value. In this case, that would be -4108.


1

In Excel, Create Numeric Arrays by Coercing Ranges

When a constant single dimensional set of numerics of mixed length, S is needed, it shall be more efficient to use [{...}] notation to declare a range and then coerce that into a numeric array rather than to use the Split(String) notation or similar.

Using this method, a change of Δbyte count=5 bytes shall be accrued for all S.

Example

For instance,

x=Split("1 2 34 567 8910")

may be written as

x=[{1,2,34,567,8910}]

It is further worth noting that while this method does not allow for direct indexing, it does allow for iteration over the for loop directly, ie

For Each s In[{1,3,5,7,9,2,4,6,8}]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.