Wskazówki dotyczące gry w golfa w VBA


16

Podobne do tego , tego i tego pytania ...

Jakie masz ogólne wskazówki na temat gry w golfa VBA? Szukam pomysłów, które można by zastosować do ogólnych problemów z golfem, które są przynajmniej nieco specyficzne VBA(np. „Usuń komentarze” nie jest odpowiedzią). Proszę zamieścić jedną wskazówkę na odpowiedź.

Chociaż pracuję z innymi językami, jestem najmocniejszy VBAi nie widzę wielu golfistów korzystających VBAz tej strony.


Konwersja na Wiki Wiki zgodnie z zasadami.
dmckee --- były moderator kociąt

Przepraszam, że z mojej strony nie było to automatyczne!
Gaffi,

Żaden kłopot. W rzeczywistości podjęli moc, aby pytania CW były od użytkowników (myślę, że nadal możesz udzielać odpowiedzi). Możesz oflagować uwagę moderatora, ale tak mało aktywności, jak CodeGolf, nie jest konieczne.
dmckee --- były moderator kociąt

2
VBA to stosunkowo szczegółowy język z kilkoma skrótami składni. Jeśli szukasz najlepszego wyniku, VBA może nie być dobrym wyborem. Jeśli chcesz doskonalić swoje umiejętności, zwiększ swoją moc.
Pan Llama,

2
@GigaWatt Szlifowanie moich umiejętności. Właściwie odkąd bawiłem się różnymi wyzwaniami, wybrałem już kilka nowych sztuczek do pracy z VBA! Nie oczekuję wygrania prawdziwych wyzwań związanych z golfem z VBA, ale to dobra praktyka. :-)
Gaffi

Odpowiedzi:


8

Wykorzystaj wartość ByRefdomyślną podczas wywoływania subskrypcji

Czasami można użyć Subpołączenia zamiast a, Functionaby zapisać kilka dodatkowych znaków ...

To ( 87 znaków)

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

można przerobić do ( 73 znaków):

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

Zauważ, że to NIE zapętla się wiecznie, choć wydaje się, że nigdy nie zmieniasz bwartości.

Powyższe nie korzysta z Functionpołączenia, ale zamiast tego wykorzystuje funkcję ByRef(„Przez odniesienie”) Subpołączenia. Oznacza to, że przekazany argument jest tą samą zmienną, co w funkcji wywołującej (w przeciwieństwie do ByValprzekazywania „By Value”, które jest kopią). Wszelkie modyfikacje przekazanej zmiennej przełożą się z powrotem na funkcję wywołującą.

Domyślnie przyjmuje wszystkie argumenty jako ByRef, więc nie ma potrzeby używania znaków do zdefiniowania tego.

Powyższy przykład może nie tłumaczyć dla Ciebie idealnie, w zależności od wartości zwracanej przez twoją funkcję. (tj. zwracanie innego typu danych niż przekazywany), ale pozwala to również na uzyskanie wartości zwracanej przy jednoczesnym modyfikowaniu oryginalnej zmiennej.

Na przykład:

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

Napisz i uruchom kod VBA w oknie natychmiastowym

Natychmiastowe okno ocenia każdą poprawną instrukcję wykonywalną VBA. Wystarczy wpisać instrukcję w Natychmiastowym oknie, tak jak w edytorze kodu. Szybko wykonuje kod VBA i może zapisać wiele dodatkowych znaków, ponieważ:

  1. Umieszczenie znaku zapytania (?) Na początku instrukcji informuje Okno Natychmiastowe o wyświetlenie wyniku twojego kodu.

enter image description here

  1. Nie musisz używać Sub i End Sub w swoim kodzie.

enter image description here


Oto przykład kodu VBA w Natychmiastowym oknie, aby odpowiedzieć na post PPCG tagiem : Litera A bez A

?Chr(88-23);

odpowiedział Joffan .


Zdjęcia kredytowe: kampus Excel


1
Jednak używa środowiska REPL? Oznacza to, że jest to tylko fragment
kodu

Myślę, że innym przykładem do dodania może być to, że możesz również tworzyć zmienne w tekście; np. a="value":?anajpierw ustawia wartość a, a następnie drukuje ją.
Greedo

6

Kontrole warunkowe przed zapętleniem

Niektóre kontrole warunkowe są zbędne, gdy są używane w połączeniu z pętlami. Na przykład Forpętla nie będzie przetwarzana, jeśli warunek początkowy jest poza zakresem warunku działania.

Innymi słowy, to ( 49 znaków):

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

Można przekształcić w to ( 24 znaki):

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

Komentarz na dole jest niepoprawny. Jeśli B = 0, wówczas zostanie wprowadzona pętla. pastebin.com/97MBB7hq
QHarr

5

Deklaracja zmienna

W większości przypadków w VBA możesz pominąć Option Explicit(często zresztą często pomijany) i pominąćDim wiele zmiennych.

W ten sposób ( 96 znaków):

Option Explicit

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

Staje się tym ( 46 znaków):

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

Jeśli potrzebujesz użyć niektórych obiektów (na przykład tablic), może być konieczne zastosowanie Dimtej zmiennej.


Chwileczkę, zaakceptowałeś własną odpowiedź na swoje pytanie. Nie fajnie, stary.
Taylor Scott

1
@TaylorScott To post na wiki - bez punktów, w tym przypadku nie ma jednej najlepszej odpowiedzi. :) Akceptuję odpowiedź ~ 5 lat temu, aby uniknąć posiadania flagi na mojej liście pytań.
Gaffi

1
@TaylorScott również, jeśli zaakceptujesz własną odpowiedź, nie dostaniesz +15 lub +2 (za akceptację)
caird coinheringaahing

5

Evaluate() I []

Jak już wspomniano wcześniej, zakodowane na stałe wywołania zakresu można zmniejszyć za pomocą [A1]zapisu w nawiasach kwadratowych . Ma jednak znacznie więcej zastosowań niż tylko to.

Według dokumentacji MSDN The Application.Evaluate()metoda przyjmuje jeden argument, który jest Name, jak określono w konwencji nazewnictwa programu Microsoft Excel.

NB [string]jest skrótem od Evaluate("string")(zwróć uwagę na ""znaki mowy oznaczające typ ciągu znaków), chociaż istnieje kilka ważnych różnic, które są omówione na końcu.

Co to wszystko oznacza pod względem użytkowania?

Zasadniczo [some cell formula here]reprezentuje komórkę w arkuszu programu Excel i można w nią umieścić prawie wszystko i wyciągnąć z niej wszystko, co można uzyskać za pomocą normalnej komórki

Co wchodzi

Podsumowując, z przykładami

  • Referencje w stylu A1. Wszystkie odniesienia są uważane za odniesienia bezwzględne.
    • [B7] zwraca odwołanie do tej komórki
    • Ponieważ referencje są bezwzględne, ?[B7].Addresszwraca"B$7$"
  • Zakresy Można używać operatorów zasięgu, przecięcia i unii (odpowiednio dwukropka, spacji i przecinka) z odniesieniami.
    • [A1:B5]zwraca odniesienie zakresu do A1:B5(Range)
    • [A1:B5 A3:D7]zwraca odniesienie zakresu do A3:B5(Przecięcie)
    • [A1:B5,C1:D5]zwraca odwołanie do zakresu A1:D5(technicznie A1:B5,C1:D5) (Unia)
  • Zdefiniowane nazwy
    • Zdefiniowane przez użytkownika, na przykład [myRange]odnoszące się do A1: G5
    • Automatyczne, jak nazwy tabel [Table1](być może mniej przydatne dla codegolf)
    • Wszystko inne można znaleźć w [Formulas]> [Name Manager]menu
  • Formuły
    • Bardzo przydatne ; dowolna formuła, która może wejść do komórki, może wejść do Evaluate()lub[]
    • [SUM(1,A1:B5,myRange)]zwraca sumę arytmetyczną wartości w zakresach myRange tutaj odnosi się do nazwy skoroszytu, a nie zmiennej VBA
    • [IF(A1=1,"true","false")](1 bajt krótszy niż odpowiednik VBA Iif([A1]=1,"true","false"))
    • Formuły tablicowe [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]- łączy wszystkie ciągi w zakresie, których długość jest większa niż 2, spacją
  • Odnośniki zewnętrzne
    • Za pomocą !operatora można odwoływać się do komórki lub nazwy zdefiniowanej w innym skoroszycie
    • [[BOOK1]Sheet1!A1]zwraca odniesienie zakresu do A1 w BOOK1 lub ['[MY WORKBOOK.XLSM]Sheet1!'A1]dla tego samego wMY WORKBOOK
    • Zwróć uwagę 'na skoroszyty ze spacjami w nazwach i brak rozszerzenia dla domyślnych nazwanych skoroszytów ( BOOK+n)
  • Obiekty wykresów (zobacz artykuł MSDN)

Uwaga: zadałem pytanie dotyczące SO dla tej informacji, więc zajrzyj tam, aby uzyskać lepsze wyjaśnienie

Co wychodzi

Podobnie do tego, co wchodzi, to, co wychodzi, obejmuje wszystko, co komórka arkusza roboczego może zwrócić. Są to standardowe typy danych Excel (i ich odpowiedniki VBA):

  • Logiczne ( Boolean)
  • Text ( String)
  • Numeryczny ( Double)
  • Error ( Variant/Error) (są to błędy nierozerwalne, tj. Nie wstrzymują wykonywania kodu, działają ?[1/0]poprawnie)

Ale jest kilka rzeczy, które można zwrócić, których komórki nie mogą:

  • Zakres odniesienia ( Range) (patrz powyższe sekcje)
  • Tablice ( Variant())

Tablice

Jak pokazano, []można go użyć do oceny formuł tablicowych, które zwracają jeden ze standardowych typów danych Excel; np. [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]który zwraca Text. EvaluateMoże jednak również zwracać tablice Varianttypu. Mogą być

Mocno zakodowane:

[{1,2;3,4}]- wyprowadza tablicę 2D: ,jest separatorem kolumn, ;oddziela wiersze. Może wyprowadzać tablicę 1D

Formuły tablicowe:

[ROW(A1:A5)]- wypisuje tablicę 2D{1,2,3,4,5} , tzn. (2,1) jest drugim elementem (jednak niektóre funkcje generują tablice 1D)

  • Z jakiegokolwiek powodu niektóre funkcje domyślnie nie zwracają tablic

[LEN(A1:A5)] wyświetla tylko długość tekstu w pierwszej komórce zakresu

  • Można je jednak zmusić do uzyskania tablic

Split([CONCAT(" "&LEN(A1:A5))]) daje tablicę 1D od 0 do 5, gdzie pierwszy element jest pusty

[INDEX(LEN(A1:A5),)]to kolejne obejście, w zasadzie musisz zastosować funkcję obsługi tablicy, aby uzyskać pożądane zachowanie zwracania tablicy, podobnie jak dodawanie bez znaczenia, RAND()aby formuły arkusza kalkulacyjnego były zmienne.

  • Zadałem pytanie dotyczące SO, aby spróbować uzyskać lepsze informacje na ten temat. Edytuj / komentuj, używając lepszych opcji, jeśli je znajdziesz

Evaluate() vs []

Istnieje kilka różnic Evaluate()i []aby mieć świadomość

  1. Strings vs hardcoded
    • Być może najważniejsza różnica, funkcja oceny przyjmuje dane wejściowe w postaci ciągu, w którym [] wymagało wpisania na stałe
    • Oznacza to, że kod można zbudować ciąg ze zmiennymi np Evaluate("SUM(B1,1,"&v &",2)")byłoby podsumować [B1], 1, 2oraz zmiennąv
  2. Tablice

    Zwracając tablicę, tylko ocena może być używana z indeksem tablicy, więc

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

    jest równa

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

Przepraszam za mamutowy post, jeśli ktoś uważa, że ​​może uczynić obszary bardziej zwięzłe / jeśli masz wskazówki do dodania, nie krępuj się. Ponadto, chociaż trochę tego zbadałem, odkryłem sporą część eksperymentując z VBA, więc jeśli zauważysz błędy w odczuciu czegoś brakuje, nie wahaj się odpowiednio skomentować / edytować!
Greedo,

1
W rzeczywistości ostatnia sekcja dotycząca tablic jest nieco wyłączona - można jej użyć w bezpośrednim okniei=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott

@TaylorScott Więc możesz, byłem całkowicie nieświadomy, że możesz ustawić / zatrzymać wartości w zmiennych, które nie zostały jeszcze zdefiniowane, ale przypuszczam, że to dlatego, że wciąż mam problemy z natychmiastowymi 1-liniowymi oknami. Zaktualizowałem odpowiednio
Greedo,

Czy to działa z Match? Próbowałem, ale zawsze zwraca błędy. Jednak zamiast zakresu mijałem tablicę.
seadoggie01

5

Połącz Nextwyciągi

Next:Next:Next

Może być skondensowany do

Next k,j,i

gdzie iteratory dla Forpętli są i, ji k- w tej kolejności.

Na przykład poniżej (69 bajtów)

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

Może być skondensowany do 65 bajtów

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

I jeśli chodzi o to, jak wpływa to na formatowanie i wcięcia, myślę, że najlepszym podejściem do rozwiązania tego problemu jest wyrównanie następnej instrukcji z najbardziej zewnętrzną dla instrukcji. Na przykład.

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

4

Zmniejszenie Ifoświadczeń

Przypisując zmienną za pomocą If ... Then ... Elsetestu warunkowego , można zmniejszyć ilość używanego kodu, eliminując End Ifgo, umieszczając cały test w jednym wierszu.

Na przykład to ( 37 znaków):

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

Można sprowadzić do tego ( 30 znaków)

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

Jeśli masz więcej niż jedną opcję zagnieżdżoną, możesz ją również zminimalizować w ten sposób:

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"!

Uwaga: :pozwala dodać więcej niż jedną linię / polecenie w Ifbloku.

W prostych przypadkach, takich jak ten, zwykle można również usunąć Else, ustawiając zmienną przed Ifsprawdzeniem ( 25 znaków):

c = a
If a < b Then c = b

Co więcej, powyższe można dodatkowo sprowadzić do tego za pomocą IIf()funkcji ( 20 znaków):

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

3

Zmniejsz Range("A1")i polub połączenia

Range("A1").Value(17 bajtów) i prostsze Range("A1")(11 bajtów) można zmniejszyć do [A1](4 bajtów)


2
Lub, ogólnie rzecz biorąc, użycie funkcji []zamiany Evaluate()w VBA jest o wiele bardziej wszechstronne niż zwykłe wywołania zasięgu. Np. Możesz go użyć do zastąpienia WorksheetFunction.FuncName(args)just [FuncName(args)], np. ?[SUMPRODUCT({1,3,5},{2,7,-1})]Lub bardzo przydatnym [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Greedo, to niezwykle ważna funkcja, o której nie wiedziałem, że powinieneś dodać ją jako własną odpowiedź.
Taylor Scott

1
Jasne, wkrótce coś napiszę. Tak Evaluate("str")lub stenografia [str]jest bardzo mocna w VBA, dopiero niedawno się dowiedziałam i myślę, że przyda się również w golfa!
Greedo

Bardzo przydatne, na tyle, że przeglądam moje odpowiedzi, aby sprawdzić, czy mogę z tego powodu zrezygnować z dowolnej liczby bajtów
Taylor Scott

3

Usuń spacje

VBA automatycznie sformatuje się, aby dodać dużo odstępów, których tak naprawdę nie potrzebuje. Tam jest odpowiedź na meta sprawia, że wiele sensu dla mnie, dlaczego możemy zniżka bajtów dodane przez auto-formatowania. Ważne jest jednak, aby zawsze sprawdzać, czy nie usunięto zbyt wiele. Na przykład, oto moja odpowiedź, która została zmniejszona prawie o 22% poprzez usunięcie spacji:

Wersja oryginalna: (188 bajtów)

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

Wersja zredukowana: (146 bajtów)

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

Jeśli skopiujesz / wkleisz zredukowaną wersję do VBA, automatycznie rozwinie się ona do oryginału. Możesz bawić się, gdzie jest to właściwe, aby usunąć spacje. Te, które do tej pory znalazłem, wydają się być zgodne ze wzorem, w którym oczekuje się, że VBA pojawi się pewne polecenie, ponieważ bez niego nie jest to prawidłowy kod. Oto niektóre, które do tej pory znalazłem:

  • Przed i po każdej operacji matematycznej: +-=/*^ itp.
  • Przed Toi Stepw Foroświadczeniu:For x=-3To 3Step 0.05
  • Faktycznie, przed każdym słowem zarezerwowanym ( To, &, Then, itd.), Jeśli jest poprzedzony dosłownym takie jak numer, ), ?,% , itd.
  • Po &połączeniu ciągów:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • Po wywołaniu funkcji: If s=StrReverse(s)Then
  • W ramach wywołań funkcji: Replace(Space(28)," ",0)

Jaka jest reguła dotycząca dodawania znaków spacji poprzez automatyczne formatowanie. Coś jak ?vs Printwidzę jest akceptowalne, ale umieszczanie deklaracji typu jak &natychmiast po zmiennej np . Debug.?a&"z"Daje Debug.Print a&; "z". ;Jest zasadniczy charakter dodany do kodu, aby uruchomić - jest to nadal dozwolone?
Greedo

2
@Greedo Widzę to tak, jak opisała to meta odpowiedź : Jeśli możesz skopiować / wkleić go do edytora, a kod się uruchomi, będzie w porządku. IE, jeśli VBA automatycznie doda znak z powrotem po wklejeniu kodu, to jest OK.
Inżynier Toast

1
@EngineerToast rzeczywiście można upuszczać jeden bajt z dysku przykład: If i=1 Then może stać If i=1Then , ponieważ, zgodnie z ogólną zasadą zarezerwowanym słowem, które następuje dosłownym, możliwe, że liczba, ), ?, %, .. etc, nie muszą być oddzielone space
Taylor Scott

1
@EngineerToast, możesz również upuścić bajt z trzeciego punktu, ponieważ możesz upuścić spacje między )(lub innym dosłownym nieliczbowym) a&
Taylor Scott

3

Przygotuj się na Pixel Art

Grafika pikselowa jest zdecydowanie jednym z najsilniejszych obszarów programu Excel, ponieważ nie ma potrzeby budowania płótna, ponieważ jest już dla Ciebie - wystarczy wprowadzić niewielkie poprawki

1) Ustaw komórki w kwadrat

Cells.RowHeight=48

lub, alternatywnie, o 1 bajt więcej, ale o wiele łatwiejsze w pracy

Cells.ColumnWidth=2

2) Pokoloruj potrzebny zakres

Każdy Rangeobiekt może być pokolorowany przez wywołanie

`MyRangeObj`.Interior.Color=`ColorValue`

Uwaga: można to i należy łączyć z innymi sztuczkami zanotowanymi na tej wiki, takimi jak odwoływanie się do zakresów za pomocą []notacji (np. [A1:R5,D6]) Nad użyciem a Cells(r,c)lub Range(cellAddress)wywołania. Ponadto, jak zauważono na tej wiki, można to połączyć z ujemną wartością koloru, aby zmniejszyć rozmiar odniesień kolorów

Szybkie referencje

Zakres odniesienia

Do komórki A1można się odwoływać na jeden z poniższych sposobów

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

a Zasięg A1:D4może być przywoływany na jeden z poniższych sposobów

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

Kolor odniesienia

Black  0
White  -1
Red    255
Aqua   -256

3

Uprość wbudowane funkcje

W przypadku częstego korzystania z niektórych funkcji należy ponownie przypisać je do funkcji zdefiniowanej przez użytkownika.

Poniższy kod ( 127 znaków) można zmniejszyć z:

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

do ( 124 znaków):

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

Łącząc to ze sztuczką ByRef , możesz zapisać jeszcze więcej znaków (do 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

Zrób to rozsądnie, ponieważ VBA wymaga wielu znaków do zdefiniowania Function. Drugi blok kodu byłby w rzeczywistości większy niż pierwszy przy dowolnej liczbie Format()połączeń mniejszej .


2
w ostatnim nie potrzebujesz połączenia, co oznacza, że a = f(w)można je zredukować dof w
Taylor Scott,

3

STDIN i STDOUT

Wprowadzanie do Subprocedur is Functionza pomocą zmiennych wejściowych

Public Sub A(ByRef B as String)

Można zmniejszyć do

Sub a(b$) 

PublicI ByRefrozmowy są domyślne dla VBA i tym samym implicite, a może (prawie) zawsze zostać pominięte.

Literał typu $wymusza bna nim typ String.

Literały innego rodzaju

  • ! Pojedynczy
  • @ Waluta
  • # Podwójnie
  • % Liczba całkowita
  • $ Strunowy
  • & Długo
  • ^ LongLong (tylko wersja 64-bitowa)

Ponadto ogólnie przyjmuje się, że można pozostawić zmienną wejściową jako typ domyślny Varianti pozostawić wszelkie błędy związane z typem bez obsługi. Na przykład. Sub E(F)w którym Foczekuje się, że będzie typu Boolean[](który zostałby przekazany do procedury podobnej doE Array(True, False, False) )

Wprowadzanie do Sub procedur i natychmiastowych funkcji okna za pośrednictwemCells

VBA nie ma w pełni funkcjonalnej konsoli, a zatem nie ma oficjalnego STDIN, a zatem pozwala niektóre grę z przekazywaniem danych wejściowych.

W programie Excel ogólnie przyjmuje się dane wejściowe z komórki lub zakresu komórek, co można zrobić podobnie

s=[A1]

która niejawnie umieszcza .valuekomórkę [A1](która może być również określana jako cells(1,1)lubrange("A1")

Przykład problemu: wyświetl dane wejściowe w oknie komunikatu

Poprzez podprogram Sub A:msgbox[A1]:End Sub

Za pośrednictwem natychmiastowej funkcji okna msgbox[A1]

Wprowadzanie za pomocą argumentów warunkowej kompilacji

Projekty VBA obsługują pobieranie argumentów z wiersza poleceń lub właściwości VBAProject (widok za pomocą eksploratora projektu -> [Twój projekt VBA] - (Kliknij prawym przyciskiem myszy) -> Właściwości VBAProject -> Argumenty warunkowej kompilacji)

Jest to w dużej mierze przydatne w przypadku wyzwań związanych z kodami błędów

Biorąc pod uwagę argument warunkowej kompilacji n=[some_value] pozwala to na wykonanie kodu, który wygeneruje kod błędu na podstawie wartości n. uwaga: wymaga to dodania 2 bajtów do kodu n=w sekcji argumentów kompilacji warunkowej w panelu właściwości VBAProject.

Przykładowy kod

...
#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
...

Wyprowadzanie przez wartość funkcji

Nie wspominając już o tym, ogólna forma cytowania poniżej jest tak zwarta, jak to tylko możliwe.

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

UWAGA: w zdecydowanej większości przypadków konwersja metody na podprogram jest bardziej bajtowa, a wyjście do okna natychmiastowego VBE (patrz poniżej)

Wyjście z Subprocedur is Functionza pośrednictwem okna natychmiastowego VBE

Wyjście do okna natychmiastowego VBE (AKA to okno debugowania VBE) jest powszechną metodą wyjściową dla VBA dla wyzwań opartych na tekście, jednak ważne jest, aby pamiętać, że Debug.Print "Text"połączenie może być znacznie golfowane.

Debug.Print "Text"

jest funkcjonalnie identyczny z

Debug.?"Text"

jako ?autoformatowanie do Print.

Wyprowadzanie z Subprocedur i VBE Immediates funkcje okna za pomocą innych metod

W rzadkich przypadkach, gdy sytuacja jest w porządku, możesz wziąć dane z niektórych bardziej trywialnych danych wejściowych dostępnych dla VBA, takich jak regulacja rozmiaru czcionki, wybór czcionki i powiększenie. (Np. Emulowanie selektora rozmiaru czcionki Word )


2

Szybka uwaga na temat formatowania

Ponieważ StackExchange używa Markdown i Prettify.js , możliwe jest dodanie flagi języka do twoich odpowiedzi na kodowanie, co ogólnie sprawia, że ​​wyglądają bardziej profesjonalnie. Chociaż nie mogę zagwarantować, że sprawi to, że będziesz lepiej grać w golfa w VBA, mogę zagwarantować, że sprawi, że będziesz wyglądać jak jesteś.

Dodanie jednej z poniższych flag zmieni się

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

do

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

Tagi językowe VBA

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

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

Uwaga: ten ostatni przekształca wszystkie segmenty kodu w twojej odpowiedzi, podczas gdy poprzedni przekształca tylko bezpośrednio następujące segmenty kodu


lang-vbco? - Dziwne, że ten format jest lepszy niżlang-vba przypadku odpowiedzi VBA.
Greedo,

1
@Greedo, to znaczy, ponieważ chociaż lang-vbazapewni podświetlanie, jest tak naprawdę tylko domyślnym podświetleniem. Najwyraźniej VBA nie zostało zaimplementowane w Prettify.js, więc będziemy musieli trzymać się podświetlenia VB
Taylor Scott

2

Wiele If .. Thenkontroli

Podobnie jak w innych językach, wiele Ifkontroli można zwykle połączyć w jedną linię, co pozwala na użycie And/ Or(tj. &&/|| W C i innych), co w VBA zastępuje zarówno a, jak Theni an End If.

Na przykład z zagnieżdżoną funkcją warunkową ( 93 znaki):

'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

może zostać ( 69 znaków):

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

Działa to również z nie zagnieżdżonymi warunkami.

Rozważ ( 84 znaków):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Może to być ( 51 znaków):

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

1
w instrukcjach If - then część „End - if” jest opcjonalna, pod warunkiem, że napiszesz kod w jednym wierszu.
Stupid_Intern

@newguy Correct. Zobacz także inną odpowiedź: codegolf.stackexchange.com/a/5788/3862
Gaffi

Powyższe oświadczenie może zostać skrócone dod=iif(a=b or c=b,0,d)
Taylor Scott

2

Kończący się For pętli

Podczas używania For pętli aNext linia nie potrzebuje nazwy zmiennej (chociaż prawdopodobnie lepiej jest użyć jej w normalnym kodowaniu).

W związku z tym,

For Variable = 1 to 100
    'Do stuff
Next Variable

można skrócić do:

For Variable = 1 to 100
    'Do stuff
Next

(Oszczędności zależą od twojej zmiennej nazwy, choć jeśli grasz w golfa, prawdopodobnie jest to tylko 1 znak + 1 spacja).


1
2 postacie, nie zapomnij policzyć miejsca!
11684

Zdarza się, że prawie nigdy nie identyfikuję zmiennej, nawet w normalnym kodzie!
dnep

2

Podziel ciąg na tablicę znaków

Czasami może być przydatne podzielenie łańcucha na poszczególne znaki, ale może to wymagać trochę kodu, aby to zrobić ręcznie w 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

Zamiast tego możesz użyć jednego wiersza, względnie minimalnego łańcucha funkcji, aby wykonać zadanie:

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

Spowoduje to przypisanie łańcucha sdo Varianttablicy a. Uważaj jednak, ponieważ ostatnim elementem w tablicy będzie pusty ciąg ( ""), z którym trzeba będzie odpowiednio się obchodzić.

Oto jak to działa: StrConvFunkcja konwertuje a Stringna inny określony format. W tym przypadku 64 = vbUnicode, więc konwertuje do formatu Unicode. W przypadku prostych ciągów ASCII wynikiem jest znak pusty (nie ciąg pusty "") wstawiany po każdym znaku.

Poniższe Splitprzekształci wynik Stringw tablicę, używając znaku pustego Chr(0)jako separatora.

Ważne jest, aby pamiętać, że Chr(0)to nie to samo co pusty ciąg "", a użycie Spliton ""nie zwróci oczekiwanej tablicy. To samo dotyczy również vbNullString(ale jeśli grasz w golfa, to dlaczego miałbyś w ogóle używać takiej pełnej stałej?).


Należy wspomnieć, że wynikowa tablica ma dodatkowy pusty ciąg na końcu.
Howard

@ Howard Tak, powinienem. To było w mojej głowie, kiedy to pisałem, musiało mi umknąć.
Gaffi,

2

Za pomocą With (czasami! Patrz przypis)

Używając With instrukcji może znacznie zmniejszyć rozmiar kodu, jeśli wielokrotnie używasz niektórych obiektów.

tj. to ( 80 znaków):

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

może być zakodowany jako ( 79 znaków):

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

Powyższe nie jest nawet najlepszym scenariuszem. Jeśli korzystasz z czegokolwiek Application, na przykład Excel.Applicationz poziomu programu Access, poprawa będzie znacznie bardziej znacząca.


* W zależności od sytuacji Withmoże, ale nie musi być bardziej wydajny ( 64 znaki):

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

2

Nieskończone pętle

Rozważyć wymianę

Do While a<b
'...
Loop

lub

Do Until a=b
'...
Loop

z przestarzałą, ale niższą liczbą bajtów

While a<b
'...
Wend

Jeśli musisz wyjść z Sublub Functionprzedwcześnie, to zamiastExit ...

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

rozważać End

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

Pamiętaj, że Endzatrzymuje wykonywanie kodu i usuwa wszystkie zmienne globalne, więc używaj mądrze


Powinieneś rozważyć przepisanie ostatniej sekcji ( Fori End), aby odzwierciedlić, że sprawa 100nigdy nie zostanie spełniona, i doda niepotrzebny bajt
Taylor Scott

Ponadto, chociaż jest to bardzo czytelne, możesz rozważyć usunięcie spacji, aby lepiej pokazać możliwe zalety tych metod (zawsze dobrze jest nadużywać automatycznego formatowania w VBA do kodowania golfa)
Taylor Scott

2

Użyj Spc(n)nad Space(n), [Rept(" ",n)]lubString(n," ")

Podczas próby wstawienia kilku spacji długości n , użyj

Spc(n)              ''  6  bytes

nad

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

Uwaga: Nie jestem pewien, dlaczego, ale wydaje się, że nie można przypisać wyniku Spc(n)do zmiennej i że należy ją wydrukować bezpośrednio - więc w niektórych przypadkach Space(n)jest to nadal najlepsza droga.


2

Zmniejsz Debug.Printi Printpołączenia

Debug.Print [some value] 

(12 bajtów; zwróć uwagę na spację końcową) można zmniejszyć do

Debug.?[some value]

(7 bajtów; zwróć uwagę na brak spacji końcowej).

Podobnie,

Print 

(6 bajtów) można zmniejszyć do

?

(1 bajt).

Ponadto, podczas działania w kontekście anonimowej funkcji bezpośredniego okna VBE, Debuginstrukcja może zostać całkowicie usunięta, a zamiast tego drukowana do bezpośredniego okna VBE za pośrednictwem? STDIN / STDOUT

Znaki specjalne

Podczas drukowania ciągów możesz również użyć znaków specjalnych zamiast &. Umożliwiają one alternatywne formaty w drukowaniu lub usuwaniu białych znaków

Aby połączyć łańcuchy zmiennych zamiast

Debug.Print s1 &s2

Możesz użyć średnika ;

Debug.?s1;s2

Ten średnik jest domyślnym zachowaniem dla kolejnych ciągów, o ile nie ma dwuznaczności, więc są one poprawne:

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

Ale nie

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

Zauważ, że a; na końcu linii pomija nową linię, ponieważ nowe linie są domyślnie dodawane po każdym wydruku. Liczenie bajtów zwróconych przez kod VBA jest przedmiotem dyskusji

Aby połączyć się tabulatorem, użyj przecinka ,(właściwie 14 spacji, ale zgodnie z)

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

Na koniec możesz użyć deklaracji typu do łączenia ciągów zamiast; każda z nich ma swój niewielki wpływ na formatowanie. Dla wszystkich poniżej a = 3.14159jest pierwszy wiersz

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

Użyj pomocnika SubdoPrint

Jeśli kod wymaga użycia więcej niż sześciu Debug.? instrukcji, możesz zmniejszyć bajty, zastępując wszystkie Debugowanie. linie z wywołaniem subwoofera, takiego jak ten poniżej. Aby wydrukować pustą linię, musisz zadzwonić, p ""ponieważ wymagany jest parametr.

Sub p(m)
Debug.?m
End Sub

1
Aby wydrukować nową linię, która wystarczy p""czy może to być niezakończony, p". Jednak w zdecydowanej większości przypadków, gdy może to mieć zastosowanie, bardziej sensowne jest użycie zmiennej łańcuchowej i drukowanie zmiennej łańcuchowej tylko na końcu.
Taylor Scott,

1

Posługiwać się Array() Choose() zamiast SelectlubIf...Then

Przypisując zmienną na podstawie wartości innej zmiennej, sensowne jest zapisanie kroków za pomocą If...Thenczeków:

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

Może to jednak zająć dużo miejsca w kodzie, jeśli do sprawdzenia jest więcej niż jedna lub dwie zmienne (i tak są ogólnie lepsze sposoby).

Zamiast tego Select Caseinstrukcja pomaga zmniejszyć rozmiar kontroli, otaczając wszystko w jednym bloku, na przykład:

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

Może to prowadzić do znacznie mniejszego kodu, ale w bardzo prostych przypadkach, takich jak ten, istnieje jeszcze bardziej wydajna metoda: Choose()Ta funkcja wybierze wartość z listy na podstawie przekazanej jej wartości.

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

Opcja wyboru ( aw tym przypadku) to wartość całkowita przekazywana jako pierwszy argument. Wszystkie kolejne argumenty są wartościami do wyboru (indeksowane 1, jak większość VBA). Wartości mogą być dowolnego typu danych, o ile są zgodne z ustawianą zmienną (tzn. Obiekty nie działają bez Setsłowa kluczowego), a nawet mogą być wyrażeniami lub funkcjami.

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

Dodatkową opcją jest użycie Arrayfunkcji, aby uzyskać ten sam efekt podczas zapisywania innej postaci:

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

Ciekawym i być może bardzo korzystnym zastosowaniem do gry w golfa jest użycie tego w połączeniu z jednym IIf()lub innym 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

Przesunięte bitowo wartości RGB

Ze względu na sposób, w jaki Excel obsługuje kolory ((bez znaku, 6-znakowa liczba szesnastkowa), możesz korzystać z liczb całkowitych ujemnie podpisanych, z których program Excel użyje tylko 6 bajtów, aby przypisać wartość koloru

Jest to nieco mylące, dlatego niektóre przykłady podano poniżej

Powiedzmy, że chcesz użyć koloru białego, który jest zapisany jako

rgbWhite

i jest równoważne z

&HFFFFFF ''#value: 16777215

aby zagrać w golfa wszystko, co musimy zrobić, to znaleźć ujemną wartość szesnastkową, która kończy się w, FFFFFFa ponieważ ujemne wartości szesnastkowe muszą mieć format FFFFXXXXXX(taki, który Xjest prawidłowym szesnastkowym) odliczający od FFFFFFFFFF( -1) do FFFF000001(-16777215 )

Wiedząc o tym, możemy uogólnić ten wzór

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

Korzystając z tego, przydatne są konwersje

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

Dobrze wiedzieć, co się tam dzieje, właśnie odkryłem to przypadkowo w tym pytaniu - ale to jasne wyjaśnienie dokładnie pokazuje, jak to działa. Należy również pamiętać, że niektóre kluczowe kolory można zmniejszyć za pomocą operatorów matematycznych; rgbWhite= 2^24-1chociaż może być jeszcze bardziej zredukowany, jeśli spudłujesz z -1, aby dostać się tam mniej więcej
Greedo

1
W rzeczywistości oto lista kolorów z ich matematycznymi reprezentacjami, które są krótsze niż wersje dodatnie lub ujemne po przecinku: &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 niekoniecznie kompletne, ale myślę, że wykonałem dość dokładną robotę
Greedo

1

Pomiń terminal " podczas drukowania do okna natychmiastowego

Biorąc pod uwagę poniższą funkcję, która ma być używana w oknie debugowania

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

Terminal "może zostać upuszczony na -1 bajt, pozostawiając ciąg niezamknięty, a program wykona to samo, bez błędów

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

Jeszcze bardziej zaskakujące jest to, że można tego dokonać w ramach w pełni zdefiniowanych podprogramów.

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

Powyższy podprogram działa zgodnie z oczekiwaniami i automatycznie formatuje do

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

1

Używaj zmiennych prawdy i falsey w warunkowych

Czasami nazywany niejawną konwersją typu - bezpośrednio przy użyciu typu liczby w If, [IF(...)]lubIIf(...) oświadczenie, używając truthy i falsey charakter tego numer może absolutnie zaoszczędzić trochę bajtów.

W języku VBA dowolna niezerowa zmienna typu liczbowego jest uważana za prawdziwą (a zatem zero 0jest jedyną wartością falsey), a zatem

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

może być skondensowane

If B Then C=B Else C=D

i dalej

C=IIf(B,B,D)

1

Arkusze adresów według nazwy

Zamiast adresowania WorkSheetobiektu przez wywołanie

Application.ActiveSheet
''  Or 
ActiveSheet   

Można użyć

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

Lub, bardziej korzystnie, można uzyskać bezpośredni dostęp do obiektu i korzystać z niego

Sheet1

1

Potęgowanie i LongLong si w 64-bitowym VBA

Ogólna forma potęgowania,

A to the power of B

Może być reprezentowany jak w VBA jako

A^B 

Ale tylko w 32-bitowych instalacjach pakietu Office , w 64 -bitowych instalacjach pakietu Office, najkrótszym sposobem, który można przedstawić bezbłędnie, jest to

A ^B

Jest tak, ponieważ w 64-bitowych wersjach VBA ^służy zarówno jako literał potęgowania, jak i LongLongznak deklaracji typu . Oznacza to, że może pojawić się dość dziwnie wyglądająca, ale poprawna składnia, taka jak

a^=2^^63^-1^

która przypisuje zmienną ado przechowywania maksymalnej wartości aLonglong


1

Kompresuj tablice bajtów jako ciąg

W przypadku wyzwań wymagających rozwiązania do przechowywania stałych danych przydatne może być skompresowanie tych danych jako pojedynczego ciągu, a następnie iteracja po nim w celu pobrania danych.

W języku VBA dowolna wartość bajtu może być bezpośrednio przekształcona na znak z

Chr(byteVal)

A a longlub integerwartość można przekonwertować na dwa znaki za pomocą

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

Tak więc dla bytetablicy algorytm kompresji wyglądałby mniej więcej tak

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$

Zwracając uwagę, że Select Casesekcja jest zaimplementowana ze względu na znaki, które nie mogą być przechowywane jako literały w ciągu.

Z powstałego ciągu, który będzie wyglądał jak

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

Dane można następnie wyodrębnić za pomocą funkcji Asci Mid, np

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

1

Używaj niewłaściwych stałych

VBA pozwala, w niektórych przypadkach, na stosowanie niepublicznych lub niewłaściwych stałych w wyrażeniach wymagających stałych wartości. Są to często wartości starsze i krótsze niż wartości prawidłowe.

Na przykład poniższe wartości mogą być użyte, gdy rng.HorizantalAlignmentwłaściwość jest w posiadaniu wartości.

NiewłaściwyWłaściwyGeneral ConstantxlHAlign  Stały11xl OgólnexlHAlignGeneral2)-4131xlLeftxlHAlignLeft3)-4108xlCenterxlHAlignCenter4-4152xlRightxlHAlignRight55xlFillxlHAlignFill6-4130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection8-4117xlDistrybucjaxlHAlignDistrybucja

Oznacza to na przykład, że ustawienie komórki tak, aby tekst był wyśrodkowany

rng.HorizantalAlignment=-4108

może zostać skrócony do

rng.HorizantalAlignment=3

poprzez zastąpienie niewłaściwej stałej wartości 3prawidłową wartością -4108. Pamiętaj, że jeśli rng.HorizantalAlignmentpobierzesz wartość właściwości, zwróci ona prawidłową wartość. W tym przypadku tak by było -4108.


1

W programie Excel utwórz tablice numeryczne, wymuszając zakresy

Gdy stały jednowymiarowy zestaw liczb o mieszanej długości, S.jest potrzebne, bardziej efektywne będzie użycie [{...}]notacji do zadeklarowania zakresu, a następnie przymuszenie go do tablicy numerycznej, niż użycie Split(String)notacji lub podobnego.

Przy użyciu tej metody zmiana Δliczba bajtów=-5 bajty będą naliczane za wszystkich S..

Przykład

Na przykład,

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

może być zapisane jako

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

Warto ponadto zauważyć, że chociaż ta metoda nie pozwala na bezpośrednie indeksowanie, umożliwia iterację bezpośrednio w pętli for, tj.

For Each s In[{1,3,5,7,9,2,4,6,8}]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.