VBAでのゴルフのヒント


16

これこれ、およびこの質問に似ています...

ゴルフの一般的なヒントは何VBAですか?私は、少なくともある程度特定のゴルフ問題全般のコーディングに適用できるアイデアを探していますVBA(たとえば、「コメントの削除」は答えではありません)。回答ごとに1つのヒントを投稿してください。

私は他の言語で仕事をしてきましたが、私はで最も強く、このサイトでVBA使用VBAしているゴルファーはあまりいません。


ポリシーに従ってコミュニティWikiに変換されました。
-dmckee

申し訳ありませんが、自動ではありませんでした!
ガフィ

問題なし。実際、彼らはCWをユーザーから遠ざけるための力を取りました(まだ答えができると思います)。モデレーターの注意を引くためにフラグを立てることもできますが、CodeGolfが取得するようなアクティビティはほとんど必要ありません。
dmckee

2
VBAは、構文のショートカットがほとんどない比較的冗長な言語です。あなたが最高のスコアを目指しているなら、VBAは良い選択ではないかもしれません。あなたのスキルを磨きたいなら、もっとパワーアップしてください。
ミスターラマ

2
@GigaWattスキルを磨く 実際、さまざまな課題をいじって以来、VBAを操作するためのいくつかの新しいトリックを既に取り上げています。VBAで実際の コードゴルフチャレンジに勝つことは期待できませんが、良い習慣です。:-)
ガフィ

回答:


8

サブルーチンをByRef呼び出すときにデフォルトを活用する

いくつかの追加文字を保存するために、aのSub代わりに呼び出しを使用することも可能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


ここではVBAコードの例は、タグ付きPPCGのポストに答えるために、イミディエイトウィンドウにあるAせずに手紙A

?Chr(88-23);

ジョファンが答えた。


クレジット画像: Excel Campus


1
ただし、REPL環境を使用しますか?ことを意味し、それだけでスニペットではなく、プログラムや関数である
coinheringaahing caird

追加する別の例として、インラインで変数を作成することも考えられます。たとえば、a="value":?a最初にの値を設定してからa、印刷します。
グリード

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の投稿です-ポイントはありません。この場合、1つのベストアンサーはありません。:)質問リストにフラグが表示されないようにするため、5年前に回答を受け入れます。
ガフィ

1
@TaylorScottまた、あなたがあなた自身の答えを受け入れた場合、あなたは+15または+2を受け取らない(受け入れたため)
共謀

5

Evaluate() そして []

前に指摘したように、ハードコードされた範囲呼び出しは、角括弧[A1]表記を使用して減らすことができます。ただし、それだけでなく、多くの用途があります。

MSDNドキュメントによると、このApplication.Evaluate()メソッドは、NameMicrosoft Excelの命名規則で定義されているように、1つの引数を取ります。

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(Intersect)への範囲参照を返します
    • [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
    • '名前にスペースが含まれているワークブックの場合、およびデフォルトの名前付きワークブックの拡張子がないことに注意してください(BOOK+n
  • チャートオブジェクト(MSDNの記事を参照)

NBこの情報についてSOで質問をしたので、より良い説明のためにそこを見てください

出てくるもの

入ってくるものと同様に、出てくるものには、ワークシートのセルが返すことができるものが含まれます。これらは、標準のExcelデータ型(およびそれに相当するVBA)です。

  • 論理(Boolean
  • テキスト(String
  • 数値(Double
  • エラー(Variant/Error)(これらは非破壊エラーです。つまり、コードの実行を停止せず、?[1/0]正常に実行されます)

ただし、セルでは返せない返される可能性のあるものがいくつかあります。

  • 範囲参照(Range)(上記のセクションを参照)
  • 配列(Variant()

配列

既に示したよう[]に、標準のExcelデータ型の1つを返す配列数式を評価するために使用できます。たとえば、[CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]どちらが返されますText。ただしEvaluateVariant型の配列を返すこともできます。これらは

ハードコーディング:

[{1,2;3,4}]-2D配列を出力します。,列セパレーターであり、;行を分離します。1D配列を出力できます

配列式:

[ROW(A1:A5)]-出力する2次元アレイを{1,2,3,4,5}(2,1)は、第2のアイテム(まだいくつかの機能出力1Dアレイ)、すなわち、

  • 何らかの理由で、一部の関数はデフォルトで配列を返しません

[LEN(A1:A5)] 範囲の最初のセルのテキストの長さのみを出力します

  • ただし、これらを強制的に配列にすることができます

Split([CONCAT(" "&LEN(A1:A5))]) 最初のアイテムが空である0から5までの1D配列を与える

[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での実験を通じてかなりの部分が見つかりました。そのため、何かが足りないと感じた間違いを見つけた場合は、それに応じてコメント/編集してください。
グリード

1
実際、配列の最後のセクションは少しオフです-イミディエイトウィンドウで使用できますi=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott

@TaylorScottだから、まだ定義されていない変数に値を設定/保持できることはまったく知りませんでしたが、それはイミディエイトウィンドウ1ライナーにまだ慣れているからだと思います。それに応じて更新しました
Greedo

これはMatchで機能しますか?試しましたが、常にエラーが返されます。ただし、範囲ではなく配列を渡していました。
seadoggie01

5

Nextステートメントを組み合わせる

Next:Next:Next

まで凝縮される可能性があります

Next k,j,i

どこのためのイテレータForループがありijk-の順で。

たとえば、以下(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、チェック全体を1行に配置することを排除することにより、使用するコードの量を減らすことができます。

たとえば、これ(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ブロック内に複数の行/コマンドを追加できます。

このような単純なケースでは、通常ElseIfチェックの前に変数を設定することで(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での[]置換の使用Evaluate()は、単なる範囲呼び出しよりもはるかに用途が広いです。例えば、あなたは交換し、それを使用することができますWorksheetFunction.FuncName(args)だけで[FuncName(args)]、このような?[SUMPRODUCT({1,3,5},{2,7,-1})]または非常に便利[MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Greedo、それは信じられないほど重要な機能であり、これを独自の回答として追加する必要があるとは知りませんでした。
テイラースコット

1
確かに、私はすぐに何かを書きます。はい、Evaluate("str")または速記[str]はVBAで非常に強力です。最近発見したばかりで、ゴルフにも役立つと思います。
グリード

私はそれのために任意の上で私の:バイトをドロップすることができるかどうかを確認するために私の答えて背中をつもりenoughsoことを、非常に便利
テイラー・スコット

3

スペースを削除

VBAは、実際には必要のない多くのスペースを追加するように自動フォーマットします。メタについての答えがあります。これは、なぜ自動フォーマットによって追加されたバイトを割引できるのか、非常に理にかなっています。ただし、削除しすぎていないことを常に確認することが重要です。例として、スペースを削除するだけでほぼ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が特定のコマンドを表示すると予想されるパターンに従っているようです。これがないと、VBAは有効なコードではないからです。ここに私がこれまでに見つけたものをいくつか示します:

  • 数学的操作の前後:+-=/*^など
  • ステートメントの前ToStepForFor 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"与えDebug.Print a&; "z"ます。;追加文字は、実行するためにコードのために不可欠である-これはまだ許可されていますか?
グリード

2
@Greedo メタの答えがそれを説明したように私はそれを見る:あなたがそれをエディタにコピー/貼り付けてコードが実行されるなら、それはOKです。IE、コードを貼り付けたときにVBAが自動的に文字を追加し直せば大丈夫です。
エンジニアトースト

1
:あなたが実際にあなたの例のオフ1つの以上のバイトをドロップすることができ@EngineerToast If i=1 Then になることがありIf i=1Then 、原則としてリテラルを次の予約語は、数は、ということが、あるため)?%、...など、Aによって分離する必要はありません。スペース
テイラースコット

1
@EngineerToastでは、3番目の箇条書きからバイトをドロップすることもできます。これは、)(またはその他の非数字リテラル)と&
Taylor Scott

3

ピクセルアートの準備

ピクセルアートは、キャンバスを構築する必要がないため、Excelの最も強力な領域の1つです。既に存在しているので、必要なことは少し調整するだけです。

1)セルを正方形にする

Cells.RowHeight=48

または、代わりに、1バイト以上、ただしはるかに使いやすい

Cells.ColumnWidth=2

2)必要な範囲に色を付ける

Range呼び出すことで、任意のオブジェクトを色付けできます

`MyRangeObj`.Interior.Color=`ColorValue`

注:これは、このwikiに記載されている他のトリック[](たとえば[A1:R5,D6]、a Cells(r,c)またはa の使用よりも表記法(たとえば)を使用して範囲を参照するなど)と組み合わせることができます。Range(cellAddress)ます。 callます。さらに、このウィキに記載されているように、これを負のカラー値と組み合わせて、カラーリファレンスのサイズを小さくすることができます

クイックリファレンス

範囲参照

セル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。2番目のコードブロックは、実際にして第一よりも大きいであろう任意の数の少ないFormat()コール。


2
最後の1つでは、割り当ての呼び出しは不要です。つまり、次のa = f(w)ように減らすことができますf w
Taylor Scott

3

STDINおよびSTDOUT

入力変数を介したSubルーチンおよびFunctionsへの入力

Public Sub A(ByRef B as String)

に減少する可能性があります

Sub a(b$) 

通話は、VBAのデフォルトのため、暗黙的であり、(ほぼ)常にドロップすることができます。PublicByRef

型リテラルは$強制的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]を指定すると、の値に基づいてエラーコードを生成するコードを実行できますnn=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イミディエイトウィンドウに出力するバイト数が増えます(以下を参照)

VBEイミディエイトウィンドウを介したSubルーチンおよびFunctions からの出力

VBEイミディエイトウィンドウ(別名VBEデバッグウィンドウ)への出力は、テキストベースのチャレンジに対するVBAの一般的な出力方法ですが、Debug.Print "Text"呼び出しが実質的にゴルフにかけられる可能性があることを覚えておくことが重要です。

Debug.Print "Text"

機能的に同じです

Debug.?"Text"

として?のオートフォーマットPrint

Sub他のメソッドを介したルーチンおよびVBEイミディエイトウィンドウ関数からの出力

まれな状況がちょうどいいときに時々 、あなたは、フォントサイズの調整、フォント選択、およびズームなどのVBAで利用できる多くの些細な入力の一部から入力を取ることがあります。(例:Wordフォントサイズセレクターのエミュレート


2

フォーマットに関する簡単な注意

StackExchangeは、使用しているため記法Prettify.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の回答よりも形式が優れている。
グリード

1
@Greedo、それは lang-vba強調表示を提供しますが、実際には単なるデフォルトの強調表示だからです。どうやらVBAはPrettify.jsに実際には実装されていないため、VBの強調表示に固執する必要があります
Taylor Scott

2

複数のIf .. Thenチェック

他の言語のように、複数Ifのチェックは、通常の使用を可能にする、単一ラインに組み合わせることができるAnd/ Or(即ち&&/ ||VBAにAの両方置き換え、Cなどで)ThenEnd 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"部分はオプションで、コードを1行で記述します。
ローハン

@newguy正解。この他の回答も参照してください:codegolf.stackexchange.com/a/5788/3862
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文字、スペースを数えることを忘れないでください!
11684

通常のコードであっても、変数を識別することはほとんどありません!
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

代わりに、1行の比較的最小限の関数チェーンを使用してジョブを完了できます。

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

これにより、文字列sVariant配列に割り当てられますa。ただし、配列の最後の項目は空の文字列("")であり、適切に処理する必要があるため、注意してください。

仕組みは次のとおりです。StrConv関数はStringを指定した別の形式にます。この場合、64 = vbUnicodeであるため、Unicode形式に変換されます。単純なASCII文字列を処理する場合、結果はnull文字(空の文字列ではなく、""各文字の後に挿入され)です。

以下 SplitString、ヌル文字を使用して、結果を配列に変換しますChr(0)を区切りとして。

Chr(0)空の文字列と同じではないことに注意することが重要です""使用Splitして""も、予想される配列は返されません。同じことが当てはまりますvbNullString(ただし、ゴルフをしている場合、なぜこのような冗長な定数を最初に使用するのでしょうか?)。


結果の配列の最後に追加の空の文字列があることに注意してください。
ハワード

@Howardはい、そうすべきです。私がこれをタイプしている間、それは私の頭の中にあった、私の心を滑らせたに違いない。
ガフィ

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

上記は最良のシナリオでさえありません。Access内からApplicationなど、で何かを使用する場合Excel.Application、改善はより重要になります。


*状況に応じて、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

SubまたはをFunction途中で終了する必要がある場合は、代わりに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会ったことはありませんとに、不要なバイト追加
テイラー・スコット

また、これは非常に読みやすいですが、空白を削除してこれらのメソッドの可能な利点をよりよく示すことを検討することもできます(コードゴルフのためにVBAのオートフォーマットを悪用することは常に良いことです)
Taylor Scott

2

使用Spc(n)を超えますSpace(n)[Rept(" ",n)]またはString(n," ")

lengthの複数のスペースを挿入しようとすると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.PrintしてPrint電話する

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

注意してください; デフォルトでは改行が印刷のたびに追加されるため、行末で改行が抑制されます。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

ヘルパーSubを使用してPrint

コードで6つ以上の Debug.?ステートメントを使用する必要がある場合、すべてのDebug。?を置き換えることでバイトを減らすことができます。以下のようなSubの呼び出しがある行。空白行を印刷するにp ""は、パラメーターが必要なので呼び出す必要があります。

Sub p(m)
Debug.?m
End Sub

1
それで新しい行を印刷するには、必要なp""場合のみ、または終了できない場合のみp"。ただし、これが当てはまる場合のほとんどは、文字列変数を使用して、最後に文字列変数のみを出力する方が理にかなっています。
テイラースコット

1

Array() Choose()代わりに使用SelectまたはのIf...Then

別の変数の値に基づいて変数を割り当てる場合If...Then、次のようにチェック付きでステップを書き出すのが理にかなっています。

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

ただし、チェックする変数が1つまたは2つ以上ある場合、これは多くのコードスペースを占有する可能性があります(とにかくそれでも一般的にはより良い方法があります)。

代わりに、このSelect Caseステートメントは、次のようにすべてを1つのブロックに入れることにより、チェックのサイズを削減するのに役立ちます。

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

これによりコードがはるかに小さくなりますが、このような非常に単純な場合には、さらに効率的な方法があります。 Choose()この関数は、渡された値に基づいてリストから値を選択します。

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

選択するオプション(aこの場合)は、最初の引数として渡される整数値です。後続のすべての引数は、選択する値です(ほとんどのVBAと同様に、1-indexed)。値は、設定されている変数と一致する限り任意のデータ型にすることができ(つまり、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

1

ビットシフトされたRGB値

Excelが色を処理する方法のため(符号なし、6文字の16進整数)、負の符号付き整数を使用できますが、Excelでは色の値を割り当てるために右の6バイトのみを使用します

これは少しわかりにくいので、いくつかの例を以下に示します

次のように保存されている白を使用するとします。

rgbWhite

と同等です

&HFFFFFF ''#value: 16777215

これを下にゴルフするには、ネガティブを見つけるだけですで終了する16進数値FFFFFFの形式でなければなりませんで、負の六角値と以降のFFFFXXXXXX(ようXからカウントダウン有効な16進です)FFFFFFFFFF-1へ)FFFF000001-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

そこに何が起こっているのかを知っているのは良いことですが、その質問で偶然発見しましたが、この明確な説明はそれがどのように機能するかを正確に示しています。留意すべきもう1つのことは、特定の主要な色を数学演算子で減らすことができるということです。rgbWhite= 2^24-1ただし、-1を逃して大まかにそこに到達した場合は、さらに減らすことができます
Greedo

1
実際、ここに、数学的な表現を持つ色のリストがあります。これは、正または負の10進数バージョンよりも短いです&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(...)ステートメントで数値型を直接使用し、その数値の真実性と偽性を使用することで、絶対に数バイト節約できます。

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^

aaの最大値を保持する変数を割り当てますLonglong


1

バイト配列を文字列として圧縮

一定のデータを保持するソリューションが必要なチャレンジでは、そのデータを単一の文字列として圧縮し、文字列全体を反復処理してデータを取得すると便利です。

VBAでは、任意のバイト値を文字に直接変換できます

Chr(byteVal)

そして、longor integer値は次のように2文字に変換されます。

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プロパティに値を保持させる場合、以下の値を使用でき ます。

不適切な適切な一般定数xlHAlign  絶え間ない11xlGeneralxlHAlignGeneral24131xlLeftxlHAlignLeft34108xlCenterxlHAlignCenter44152xlRightxlHAlignRight55xlFillxlHAlignFill64130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection84117xlDistributedxlHAlignDistributed

これは、たとえば、テキストの中央にセルを設定することを意味します

rng.HorizantalAlignment=-4108

に短縮することができます

rng.HorizantalAlignment=3

不適切な定数値3を適切な値に置き換えます-4108rng.HorizantalAlignmentプロパティ値を取得すると、適切な値が返されることに注意してください。この場合、それはになります-4108


1

Excelで、範囲を強制して数値配列を作成する

長さが混在する一定の単一次元数値セットの場合、 S必要な場合は、[{...}]表記法を使用して範囲を宣言し、そのSplit(String)表記法などを使用するよりも、数値配列に強制する 方が効率的です。

この方法を使用すると、 バイト数=5 バイト すべてのために発生しなければならない S

例えば、

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

として書かれている可能性があります

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

このメソッドは直接インデックス付けを許可しませんが、forループを介した直接の反復を許可します。つまり、

For Each s In[{1,3,5,7,9,2,4,6,8}]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.