Suggerimenti per giocare a golf in VBA


16

Simile a questo , questo e questa domanda ...

Quali consigli generali hai per giocare a golf VBA? Sto cercando idee che possono essere applicate ai problemi del codice golf in generale, che sono almeno in qualche modo specifiche VBA(ad esempio "rimuovere i commenti" non è una risposta). Si prega di inviare un suggerimento per risposta.

Mentre ho lavorato con altre lingue, sono più forte in VBA, e non vedo molti golfisti che usano VBAquesto sito.


Convertito in Wiki della community secondo la politica.
dmckee,

Mi dispiace che non sia stato automatico da parte mia!
Gaffi,

Nessun problema. In realtà, hanno preso il potere di fare domande in CW agli utenti (puoi ancora fare delle risposte, credo). Potresti segnalare l'attenzione del moderatore, ma non è necessaria la minima attività di CodeGolf.
dmckee,

2
VBA è un linguaggio relativamente dettagliato con poche scorciatoie da sintassi. Se stai per ottenere il miglior punteggio, VBA potrebbe non essere una buona scelta. Se stai cercando di affinare le tue abilità, più potere per te.
Mr. Llama,

2
@GigaWatt Affina le mie capacità. In realtà da quando ho giocato con diverse sfide, ho già raccolto alcuni nuovi trucchi per lavorare con VBA! Non mi aspetto di vincere nessuna vera sfida di code-golf con VBA, ma è una buona pratica. :-)
Gaffi

Risposte:


8

Sfrutta il ByRefvalore predefinito quando chiami i sottotitoli

A volte è possibile utilizzare una Subchiamata al posto di a Functionper salvare alcuni caratteri aggiuntivi ...

Questo ( 87 caratteri)

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

può essere rielaborato in ( 73 caratteri):

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

Si noti che questo NON verrà ripetuto per sempre, anche se sembra che non si stia riassegnando bil valore.

Quanto sopra non usa una Functionchiamata, ma sfrutta invece la funzionalità ByRef("Per riferimento") della Subchiamata. Ciò significa che l'argomento passato è la stessa variabile della funzione chiamante (al contrario del passaggio ByVal"Per valore", che è una copia). Eventuali modifiche alla variabile passata si tradurranno nuovamente nella funzione chiamante.

Per impostazione predefinita, accetta tutti gli argomenti come ByRef, quindi non è necessario utilizzare i caratteri per definirlo.

L'esempio sopra potrebbe non tradursi perfettamente per te, a seconda del valore di ritorno della tua funzione. (ovvero restituendo un tipo di dati diverso da quello che viene passato), ma ciò consente anche la possibilità di ottenere un valore di ritorno pur modificando la variabile originale.

Per esempio:

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

Scrivi ed esegui il codice VBA nella finestra immediata

La finestra immediata valuta qualsiasi istruzione eseguibile VBA valida. Basta inserire una dichiarazione nella finestra immediata come nell'editor di codice. Esegue rapidamente il codice VBA e può salvare molti caratteri aggiuntivi perché:

  1. Mettere il punto interrogativo (?) All'inizio dell'istruzione indica alla finestra immediata di visualizzare il risultato del codice.

inserisci qui la descrizione dell'immagine

  1. Non è necessario utilizzare un Sottotitolo e Sottotitolo nel codice.

inserisci qui la descrizione dell'immagine


Ecco l'esempio del codice VBA nella finestra immediata per rispondere al post di PPCG con tag : La lettera A senza A

?Chr(88-23);

rispose Joffan .


Immagini di credito: Excel Campus


1
Che utilizza un ambiente REPL però? Ciò significa che è solo uno snippet, non un programma o una funzione
caird coinheringaahing

Penso che un altro esempio da aggiungere potrebbe essere che puoi anche creare variabili in linea; ad es. a="value":?aprima imposta il valore di a, quindi lo stampa.
Greedo

6

Controlli condizionali prima del loop

Alcuni controlli condizionali sono ridondanti se utilizzati in combinazione con loop. Ad esempio, aFor ciclo non verrà elaborato se la condizione iniziale non rientra nell'ambito della condizione in esecuzione.

In altre parole, questo ( 49 caratteri):

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

Può essere trasformato in questo ( 24 caratteri):

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

Il commento in fondo non è corretto. Se B = 0, verrà inserito il loop. pastebin.com/97MBB7hq
QHarr

5

Dichiarazione variabile

Nella maggior parte dei casi in VBA, puoi tralasciare Option Explicit(spesso omesso di default, comunque) e saltareDim molte delle tue variabili.

Nel fare ciò, questo ( 96 caratteri ):

Option Explicit

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

Diventa questo ( 46 caratteri):

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

Se è necessario utilizzare determinati oggetti (ad esempio array), potrebbe essere necessario utilizzare Dimquella variabile.


Aspetta un secondo, hai accettato la tua risposta alla tua domanda. Non bello, amico.
Taylor Scott,

1
@TaylorScott È un post wiki - nessun punto, e in questo caso non esiste una sola risposta migliore. :) Accetto la risposta ~ 5 anni fa per evitare di avere una bandiera nel mio elenco di domande.
Gaffi,

1
@TaylorScott anche se accetti la tua risposta, non ricevi +15 o +2 (per accettare)
caird coinheringaahing

5

Evaluate() E []

Come è stato sottolineato in precedenza, le chiamate di intervallo codificate possono essere ridotte utilizzando le parentesi quadre [A1] notazione . Tuttavia ha molti più usi oltre a quello.

Secondo la documentazione MSDN , ilApplication.Evaluate() metodo accetta un singolo argomento, ovvero aName , come definito dalla convenzione di denominazione di Microsoft Excel.

NB [string]è una scorciatoia per Evaluate("string")(notare il"" segni vocali che indicano il tipo di dati stringa), sebbene ci siano alcune differenze importanti che sono coperte alla fine.

Cosa significa tutto ciò in termini di utilizzo?

In sostanza, [some cell formula here]rappresenta una cella in un foglio di lavoro Excel, e puoi inserire praticamente qualsiasi cosa al suo interno e ricavarne tutto ciò che potresti con una normale cella

Cosa succede

In sintesi, con esempi

  • Riferimenti in stile A1. Tutti i riferimenti sono considerati riferimenti assoluti.
    • [B7] restituisce un riferimento a quella cella
    • Poiché i riferimenti sono assoluti, i ?[B7].Addressrendimenti"B$7$"
  • Intervalli È possibile utilizzare gli operatori range, intersect e union (due punti, spazio e virgola, rispettivamente) con riferimenti.
    • [A1:B5]restituisce un riferimento di intervallo a A1:B5(Intervallo)
    • [A1:B5 A3:D7]restituisce un riferimento di intervallo a A3:B5(Intersezione)
    • [A1:B5,C1:D5]restituisce un riferimento di intervallo a A1:D5(tecnicamente A1:B5,C1:D5) (Unione)
  • Nomi definiti
    • Definito dall'utente come [myRange]riferimento ad A1: G5
    • Automatico, come i nomi delle tabelle [Table1](forse meno utile per codegolf)
    • Qualsiasi altra cosa puoi trovare nel menu [Formulas]>[Name Manager]
  • formule
    • Molto utile ; qualsiasi formula che può andare in una cella può entrare Evaluate()o[]
    • [SUM(1,A1:B5,myRange)]restituisce la somma aritmetica dei valori negli intervalli myRange qui si riferisce a un nome di cartella di lavoro non a una variabile VBA
    • [IF(A1=1,"true","false")] (1 byte più corto dell'equivalente vba Iif([A1]=1,"true","false") )
    • Formule di matrice [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]: unisce tutte le stringhe nell'intervallo la cui lunghezza è maggiore di 2 con uno spazio
  • Riferimenti esterni
    • Puoi usare il ! operatore per fare riferimento a una cella o a un nome definito in un'altra cartella di lavoro
    • [[BOOK1]Sheet1!A1]restituisce un riferimento di intervallo a A1 in BOOK1 o ['[MY WORKBOOK.XLSM]Sheet1!'A1]per lo stesso inMY WORKBOOK
    • Nota 'per le cartelle di lavoro con spazi nei loro nomi e la mancanza di estensione per le cartelle di lavoro con nome predefinito ( BOOK+n)
  • Oggetti grafico (vedi l'articolo MSDN)

NB Ho fatto una domanda su SO per queste informazioni, quindi dai un'occhiata qui per una spiegazione migliore

Cosa viene fuori

Simile a ciò che accade, ciò che viene fuori include tutto ciò che una cella del foglio di lavoro può restituire. Questi sono i tipi di dati Excel standard (e i loro equivalenti VBA):

  • Logico (Boolean )
  • Testo (String )
  • Numerico (Double )
  • Errore ( Variant/Error) (si tratta di errori senza interruzione, ad es. Non fermano l'esecuzione del codice, vengono ?[1/0]eseguiti correttamente)

Ma ci sono alcune cose che possono essere restituite che le celle non possono:

  • Intervallo di riferimento ( Range) (vedere le sezioni precedenti)
  • Array ( Variant())

Array

Come è stato mostrato, []può essere utilizzato per valutare le formule di array che restituiscono uno dei tipi di dati Excel standard; ad es. [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]quale ritorna Text. Tuttavia, Evaluatepuò anche restituire matrici di Varianttipo. Questi possono essere

hardcoded:

[{1,2;3,4}]- genera un array 2D: ,è il separatore di colonne, ;separa le righe. Può emettere un array 1D

Formule di matrice:

[ROW(A1:A5)]- genera un array 2D{1,2,3,4,5} , ovvero (2,1) è il secondo elemento (ma alcune funzioni generano array 1D)

  • Per qualsiasi motivo, alcune funzioni non restituiscono array per impostazione predefinita

[LEN(A1:A5)] genera solo la lunghezza del testo nella prima cella di un intervallo

  • Tuttavia, questi possono essere costretti a fornire array

Split([CONCAT(" "&LEN(A1:A5))]) fornisce un array 1D da 0 a 5, in cui il primo elemento è vuoto

[INDEX(LEN(A1:A5),)]è un'altra soluzione alternativa, in sostanza è necessario utilizzare una funzione di gestione dell'array per ottenere il comportamento di ritorno dell'array desiderato, simile all'aggiunta in un senso RAND()per rendere volatili le formule del foglio di lavoro.

  • Ho fatto una domanda su SO per cercare di ottenere informazioni migliori su questo, per favore modifica / commenta con opzioni migliori se le trovi

Evaluate() vs []

Ci sono alcune differenze tra Evaluate()e []di cui essere consapevoli

  1. Stringhe vs hardcoded
    • Forse la differenza più importante, Evaluate accetta un input di stringa in cui [] ha richiesto un input hardcoded
    • Questo significa che il codice può costruire la stringa con variabili per esempio Evaluate("SUM(B1,1,"&v &",2)")sarebbe riassumere [B1], 1, 2e variabiliv
  2. Array

    Quando si restituisce una matrice, è possibile utilizzare solo Valuta con un indice di matrice, quindi

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

    è equivalente a

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

Ci scusiamo per il post mastodontico, se qualcuno ritiene di poter rendere le aree più concise / se hai suggerimenti da aggiungere, sentiti libero. Inoltre, anche se ho studiato un po 'di questo, è stata trovata una buona parte sperimentando in VBA, quindi se noti errori di sentire che manca qualcosa, non esitare a commentare / modificare di conseguenza!
Greedo,

1
In realtà l'ultima sezione sugli array è un po 'fuori - può essere usata nella finestra immediatai=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott

@TaylorScott Così puoi, non ero assolutamente a conoscenza del fatto che tu potessi impostare / conservare valori in variabili che non erano già state definite, ma suppongo che sia perché sto ancora facendo i conti con la finestra 1-line della finestra immediata. Si sono aggiornati di conseguenza
Greedo il

Funziona con Match? Ho provato, ma restituisce sempre errori. Tuttavia, stavo passando un array anziché un intervallo.
seadoggie01

5

Combina Nextdichiarazioni

Next:Next:Next

Può essere ridotto a

Next k,j,i

dove gli iteratori per i Forcicli sono i, je k- in questo ordine.

Ad esempio il seguente (69 byte)

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

Può essere ridotto a 65 byte

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

E per quanto riguarda il modo in cui ciò influisce sulla formattazione e sul rientro, penso che l'approccio migliore per gestirlo sia quello di allineare la frase successiva a quella più esterna. Per esempio.

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

4

IfDichiarazioni riduttive

Quando si assegna una variabile utilizzando un If ... Then ... Elsecontrollo condizionale , è possibile ridurre la quantità di codice utilizzato eliminando il End Ifmettendo l'intero controllo su una riga.

Ad esempio, questo ( 37 caratteri):

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

Può essere ridotto a questo ( 30 caratteri)

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

Se hai più di un condizionale nidificato, puoi minimizzarlo anche in questo modo:

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

Si noti che :consente di aggiungere più di una riga / comando all'interno di un Ifblocco.

In casi semplici come questo, di solito puoi anche rimuovere Elseimpostando la variabile prima del Ifcontrollo ( 25 caratteri):

c = a
If a < b Then c = b

Ancora meglio, quanto sopra può essere ulteriormente ridotto a questo usando la IIf()funzione ( 20 caratteri):

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

3

Riduci Range("A1")e metti mi piace

Range("A1").Value(17 byte) e il più semplice Range("A1")(11 byte) può essere ridotto fino a [A1](4 byte)


2
O in generale, l'uso di []sostituire Evaluate()in VBA è molto più versatile rispetto alle chiamate a distanza. Ad esempio puoi usarlo per sostituirlo WorksheetFunction.FuncName(args)con just [FuncName(args)], come ?[SUMPRODUCT({1,3,5},{2,7,-1})]o l'utilissimo [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Greedo, questa è una funzionalità incredibilmente importante di cui non ero a conoscenza che dovresti aggiungere questa come sua risposta.
Taylor Scott,

1
Certo, scriverò qualcosa tra poco. Sì Evaluate("str")o la stenografia [str]è molto potente in VBA, l'ho scoperto solo di recente e suppongo che sarà utile anche per il golf!
Greedo,

Molto utile, abbastanza per tornare indietro attraverso le mie risposte per vedere se riesco a perdere il mio conto su qualsiasi per questo
Taylor Scott,

3

Rimuovi spazi

VBA si formatterà automaticamente per aggiungere molto spazio che non è effettivamente necessario. C'è una risposta su meta che ha molto senso per me perché possiamo scartare i byte aggiunti dalla formattazione automatica. Tuttavia, è importante verificare sempre di non aver rimosso troppo. Per un esempio, ecco una mia risposta che è stata ridotta di quasi il 22% semplicemente rimuovendo gli spazi:

Versione originale: (188 byte)

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

Versione ridotta: (146 byte)

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

Se copi / incolli la versione ridotta in VBA, si espanderà automaticamente nell'originale. Puoi giocare con dove è valido rimuovere gli spazi. Quelli che ho trovato finora sembrano tutti seguire il modello in cui si prevede che VBA appaia un certo comando perché, senza di esso, non è un codice valido. Eccone alcuni che ho trovato finora:

  • Prima e dopo qualsiasi operazione matematica: +-=/*^ ecc.
  • Prima Toe Stepin aFor dichiarazione:For x=-3To 3Step 0.05
  • In realtà, prima di ogni parola riservata ( To, &, Then, etc.) se è preceduta da un tale letterale come un numero, ), ?,% , etc.
  • Dopo il & combinato le stringhe:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • Dopo le chiamate di funzione: If s=StrReverse(s)Then
  • Nelle chiamate di funzione: Replace(Space(28)," ",0)

Qual è la regola sui caratteri non spaziali aggiunti tramite la formattazione automatica. Qualcosa come ?vs PrintVedo è accettabile, ma mettere alla dichiarazione del tipo come &immediatamente dopo una variabile, ad esempio, Debug.?a&"z"Debug.Print a&; "z". Il ;carattere aggiunto è essenziale per l'esecuzione del codice: è ancora consentito?
Greedo,

2
@Greedo lo vedo come descritto dalla meta risposta : se riesci a copiarlo / incollarlo nell'editor e il codice verrà eseguito, va bene. Ad esempio, se VBA aggiunge automaticamente il carattere indietro quando si incolla il codice, allora va bene.
Ingegnere Toast,

1
@EngineerToast si può effettivamente rilasciare un altro byte di fuori del vostro esempio: If i=1 Then può diventare If i=1Then , perché, come regola generale una parola riservata che segue un letterale, essere che un numero, ), ?, %, .. ecc, non ha bisogno di essere separati da un spazio
Taylor Scott,

1
@EngineerToast, puoi anche rilasciare un byte dal tuo terzo punto elenco in quanto puoi eliminare gli spazi tra un )(o qualsiasi altro valore letterale non numerico) e&
Taylor Scott

3

Preparati per Pixel Art

La pixel art è di gran lunga una delle aree più forti di Excel, in quanto non è necessario costruire una tela, poiché è già lì per te - tutto ciò che devi fare è apportare alcune piccole modifiche

1) Rendi le celle quadrate

Cells.RowHeight=48

o, in alternativa, per 1 byte in più, ma molto più facile da lavorare

Cells.ColumnWidth=2

2) Colora la gamma necessaria

Qualsiasi Rangeoggetto può essere colorato chiamando

`MyRangeObj`.Interior.Color=`ColorValue`

Nota: questo può e deve essere combinato con altri trucchi annotati in questo wiki, come ad esempio intervalli di riferimento mediante l'uso della []notazione (ad esempio [A1:R5,D6]) sull'uso di una Cells(r,c)o una Range(cellAddress)chiamata. Inoltre, come notato in questo wiki, questo può essere combinato con un valore di colore negativo per ridurre la dimensione dei riferimenti di colore

Riferimenti rapidi

Gamma di riferimento

È A1possibile fare riferimento alla cella in uno dei seguenti modi

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

e l'intervallo A1:D4può essere referenziato in uno dei seguenti modi

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

Riferimento colore

Black  0
White  -1
Red    255
Aqua   -256

3

Semplifica le funzioni integrate

Quando si utilizzano frequentemente determinate funzioni, riassegnarle a una funzione definita dall'utente.

Il seguente codice ( 127 caratteri) può essere ridotto da:

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

a ( 124 caratteri):

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

Combinando questo con il trucco ByRef , puoi salvare ancora più personaggi (fino a 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

Fallo con giudizio, dato che VBA occupa molti personaggi per definire a Function. Il secondo blocco di codice sarebbe effettivamente più grande del primo con un numero minore di Format()chiamate.


2
nell'ultimo, non è necessaria la chiamata di assegnazione, il che significa che a = f(w)può essere ridotto af w
Taylor Scott

3

STDIN e STDOUT

Introduzione a Subroutine et Functiontramite variabili di input

Public Sub A(ByRef B as String)

Può essere ridotto a

Sub a(b$) 

Le chiamate Publice ByRefsono predefinite per VBA e quindi implicite e possono (quasi) essere sempre eliminate.

Le $forze letterali del tipo bdevono essere del tipoString .

Altri letterali di tipo

  • ! singolo
  • @ Moneta
  • # Doppio
  • % Numero intero
  • $ Corda
  • & Lungo
  • ^ LongLong (solo 64 bit)

Inoltre, è generalmente accettato che è possibile lasciare la variabile di input come tipo predefinito Variante lasciare non gestiti eventuali errori basati sul tipo. Per esempio. Sub E(F)in cui Fci si aspetta che sia di tipo Boolean[](che sarebbe passato alla routine comeE Array(True, False, False) )

Inserimento di Subroutine e funzioni della finestra immediata tramiteCells

VBA non ha una console completamente funzionale e quindi non ha alcun STDIN ufficiale , e quindi consente per alcuni gioco con il passaggio di ingresso.

In Excel, è generalmente accettato di prendere input da una cella o intervallo di celle, che può essere fatto come

s=[A1]

che inserisce implicitamente il .valuedalla cella [A1](che può anche essere indicato come cells(1,1)orange("A1")

Esempio Problema: visualizzare l'input in una finestra di messaggio

Tramite la subroutine Sub A:msgbox[A1]:End Sub

Tramite la funzione Finestra immediata msgbox[A1]

Inserimento tramite argomenti di compilazione condizionale

I progetti VBA supportano l'acquisizione di argomenti dalla riga di comando o tramite le proprietà VBAProject (visualizza tramite Esplora progetti -> [Il tuo progetto VBA] - (clic destro) -> Proprietà VBAProject -> Argomenti di compilazione condizionale)

Questo è molto utile per sfide del codice di errore

Dato l'argomento della compilazione condizionale n=[some_value] ciò consente di eseguire codice che produrrà un codice di errore, basato sul valore di n. nota, ciò richiede un'aggiunta di 2 byte al codice per la n=sezione degli argomenti di compilazione condizionale del riquadro delle proprietà di VBAProject.

Codice di esempio

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

Emissione tramite il valore della funzione

Non c'è molto da dire qui, la forma generale di cui sotto è più o meno compatta.

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

NOTA: nella stragrande maggioranza dei casi è più byte convertire il metodo in una subroutine e inviarlo alla finestra immediata di VBE (vedi sotto)

Emissione da Subroutine et Functiontramite la finestra VBE Immediates

L'output alla finestra di VBE immediatamente (AKA la finestra di debug di VBE) è un metodo di output comune per VBA per sfide basate sul testo, tuttavia, è importante ricordare che la Debug.Print "Text"chiamata può essere sostanzialmente giocata a golf.

Debug.Print "Text"

è funzionalmente identico a

Debug.?"Text"

come ?formati automatici per Print.

Emissione da Subroutine e VBE immediatamente le funzioni della finestra tramite altri metodi

In rare occasioni, quando la situazione è giusta, puoi prendere input da alcuni degli input più banali disponibili per VBA come il regolatore della dimensione del font, il selettore del font e lo zoom. (Ad es. Emulazione del selettore della dimensione del carattere di Word )


2

Nota rapida sulla formattazione

Perché StackExchange utilizza Markdown e Prettify.js , è possibile aggiungere un flag di lingua alle risposte di codifica, il che generalmente le rende più professionali. Anche se non posso garantire che questo ti renderà migliore a giocare a golf in VBA, posso garantire che ti farà sembrare come sei.

L'aggiunta di uno dei flag in basso si trasformerà

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

per

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

Tag lingua VBA

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

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

Nota: quest'ultimo trasforma tutti i segmenti di codice nella tua risposta, mentre il precedente trasforma solo i segmenti di codice immediatamente seguenti


lang-vbeh? - Strano che formatta meglio rispetto lang-vbaalle risposte VBA.
Greedo,

1
@Greedo, questo perché mentre lang-vbafornirà l'evidenziazione, in realtà è solo l'evidenziazione predefinita. Apparentemente VBA non è stato effettivamente implementato in Prettify.js, quindi dovremo attenerci all'evidenziazione VB
Taylor Scott

2

If .. ThenControlli multipli

Come in altre lingue, in Ifgenere è possibile combinare più controlli in un'unica riga, consentendo l'uso di And/ Or(ovvero &&/ ||in C e altri), che in VBA sostituisce sia a Thenche a End If.

Ad esempio, con un condizionale nidificato ( 93 caratteri):

'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

può diventare ( 69 caratteri):

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

Questo funziona anche con i condizionali non nidificati.

Considera ( 84 caratteri):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Questo può diventare ( 51 caratteri):

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

1
in If - then istruzioni la parte "End - if" è facoltativa fornire il codice nella riga singola.
Stupid_Intern

@newguy Correct. Vedi anche questa altra risposta: codegolf.stackexchange.com/a/5788/3862
Gaffi

L'affermazione di cui sopra può essere ridotta ulteriormente ad=iif(a=b or c=b,0,d)
Taylor Scott,

2

Ending ForLoops

Quando si usano i Forloop, una Nextlinea non ha bisogno di un nome di variabile (sebbene sia probabilmente meglio usarlo nella normale codifica).

Perciò,

For Variable = 1 to 100
    'Do stuff
Next Variable

può essere abbreviato in:

For Variable = 1 to 100
    'Do stuff
Next

(I risparmi dipendono dal nome della variabile, anche se se stai giocando a golf, probabilmente è solo 1 carattere + 1 spazio.)


1
2 personaggi, non dimenticare di contare lo spazio!
11684

Non capisco quasi mai di identificare la variabile, anche nel normale codice!
dnep

2

Dividi una stringa in una matrice di caratteri

A volte può essere utile suddividere una stringa in singoli caratteri, ma può essere necessario un po 'di codice per farlo manualmente in 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

Invece, è possibile utilizzare una singola riga, catena di funzioni relativamente minima per eseguire il lavoro:

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

Questo assegnerà la stringa sa Variantmatrice a. Fare attenzione, tuttavia, poiché l'ultimo elemento dell'array sarà una stringa vuota ( ""), che dovrà essere gestita in modo appropriato.

Ecco come funziona: la StrConvfunzione converte un Stringin un altro formato specificato. In questo caso, 64 = vbUnicode, quindi viene convertito in un formato Unicode. Quando si ha a che fare con stringhe ASCII semplici, il risultato è un carattere null (non una stringa vuota,"" ) inserito dopo ogni carattere.

Quanto segue Splitconvertirà quindi il risultante Stringin un array, usando il carattere nullChr(0) come delimitatore.

È importante notare che Chr(0)non è uguale alla stringa vuota ""e l'utilizzo di Spliton ""non restituirà l'array che ci si potrebbe aspettare. Lo stesso vale anche per vbNullString(ma se stai giocando a golf, allora perché dovresti usare una costante così dettagliata?).


Si noti che l'array risultante ha una stringa vuota aggiuntiva alla fine.
Howard,

@Howard Sì, dovrei. Era nella mia testa mentre scrivevo questo, deve essermi sfuggito di mente.
Gaffi,

2

utilizzando With (a volte! Vedi nota a piè di pagina)

Usando il With dell'istruzione può ridurre significativamente la dimensione del codice se si utilizzano ripetutamente alcuni oggetti.

cioè questo ( 80 caratteri):

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

può essere codificato come ( 79 caratteri):

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

Quanto sopra non è nemmeno lo scenario migliore. Se si utilizza qualcosa con Application, ad esempio Excel.Applicationda Access, il miglioramento sarà molto più significativo.


* A seconda della situazione, Withpuò o meno essere più efficiente di questo ( 64 caratteri):

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

2

Cicli infiniti

Considerare la sostituzione

Do While a<b
'...
Loop

o

Do Until a=b
'...
Loop

con il conteggio dei byte antiquato ma inferiore

While a<b
'...
Wend

Se devi uscire a Subo Functionprematuramente, invece diExit ...

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

ritenere End

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

Nota che Endinterrompe tutta l'esecuzione del codice e cancella tutte le variabili globali, quindi usa saggiamente


Dovresti considerare di riscrivere l'ultima sezione ( Fore End) per riflettere che il caso 100non sarà mai soddisfatto e aggiunge un byte non necessario
Taylor Scott

Inoltre, sebbene sia molto leggibile, potresti considerare di rimuovere lo spazio bianco per mostrare meglio i possibili benefici di questi metodi (è sempre bene abusare dell'autoformatting in VBA per codegolfing)
Taylor Scott,

2

Utilizzare Spc(n)sopra Space(n), [Rept(" ",n)]oString(n," ")

Quando si tenta di inserire più spazi di lunghezza n, utilizzare

Spc(n)              ''  6  bytes

al di sopra di

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

Nota: non sono sicuro del perché, ma sembra che non sia possibile assegnare l'output di Spc(n) una variabile e che debba piuttosto essere stampato direttamente, quindi in alcuni casi Space(n)è ancora il modo migliore di procedere.


2

Ridurre Debug.Print e Printchiama

Debug.Print [some value] 

(12 byte; notare lo spazio finale) può essere ridotto a

Debug.?[some value]

(7 byte; notare la mancanza di spazio finale).

Allo stesso modo,

Print 

(6 byte) può essere ridotto a

?

(1 byte).

Inoltre, quando si opera nel contesto di una funzione di finestra immediata VBE anonima, è possibile che l' Debugistruzione venga rilasciata completamente e invece stampata sulla finestra immediata di VBE tramite? può presumere che la STDIN / STDOUT

Personaggi speciali

Quando si stampano stringhe, è possibile utilizzare anche caratteri speciali al posto di &. Questi consentono formati alternativi nella rimozione di spazi stampati o stampati

Per unire stringhe variabili, anziché

Debug.Print s1 &s2

Puoi usare un punto e virgola ;

Debug.?s1;s2

Questo punto e virgola è il comportamento predefinito per le stringhe consecutive, purché non vi siano ambiguità, quindi sono valide:

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

Ma no

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

Si noti che a; alla fine di una riga viene soppressa una nuova riga, poiché le nuove righe vengono aggiunte per impostazione predefinita dopo ogni stampa. Il conteggio dei byte restituiti dal codice VBA è in discussione

Per unirti a una scheda usa una virgola ,(in realtà 14 spazi, ma secondo)

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

Infine, puoi usare le dichiarazioni di tipo per unire stringhe invece di; ognuna con il suo leggero effetto sulla formattazione. Per tutto quanto sotto a = 3.14159è la prima riga

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

Usa un aiuto SubperPrint

Se il codice richiede l'utilizzo di più di sei Debug.? istruzioni, è possibile ridurre i byte sostituendo tutto il debug. linee con una chiamata a un sub come quella qui sotto. Per stampare una riga vuota è necessario chiamare p ""poiché è richiesto un parametro.

Sub p(m)
Debug.?m
End Sub

1
Per stampare una nuova linea con quello si sarebbe solo bisogno p""o se può essere terminato, p". Tuttavia, nella stragrande maggioranza dei casi in cui ciò può applicarsi, ha più senso usare una variabile stringa e stampare solo la variabile stringa alla fine.
Taylor Scott,

1

Utilizzare Array() Choose()invece di SelectoIf...Then

Quando si assegna una variabile in base al valore di un'altra variabile, ha senso scrivere i passaggi con i If...Thencontrolli, in questo modo:

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

Tuttavia, questo può occupare molto spazio nel codice se ci sono più di una o due variabili da controllare (ci sono comunque modi generalmente migliori di farlo comunque).

Invece, l' Select Caseistruzione aiuta a ridurre la dimensione dei controlli racchiudendo tutto in un blocco, in questo modo:

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

Questo può portare a un codice molto più piccolo, ma per casi molto semplici come questo, esiste un metodo ancora più efficiente: Choose()questa funzione sceglierà un valore da un elenco, in base al valore passato ad esso.

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

L'opzione per selezionare ( ain questo caso) è un valore intero passato come primo argomento. Tutti gli argomenti successivi sono i valori tra cui scegliere (1 indicizzato, come la maggior parte dei VBA). I valori possono essere di qualsiasi tipo di dati purché corrispondano alla variabile impostata (ovvero gli oggetti non funzionano senza ilSet parola chiave) e possono anche essere espressioni o funzioni.

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

Un'opzione aggiuntiva è quella di utilizzare la Arrayfunzione per ottenere lo stesso effetto mentre si salva un altro personaggio:

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

Un uso interessante e forse molto utile per giocare a golf è quello di usarlo insieme a uno IIf()o l'altro 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

Valori RGB con spostamento dei bit

A causa del modo in cui Excel gestisce i colori, (intero esadecimale a 6 caratteri senza segno) è possibile utilizzare numeri interi con segno negativo, di cui Excel utilizzerà solo i 6 byte giusti per assegnare un valore di colore

Questo è un po 'confuso, quindi alcuni esempi sono forniti di seguito

Diciamo che vuoi usare il colore bianco, che è memorizzato come

rgbWhite

ed è equivalente a

&HFFFFFF ''#value: 16777215

al golf questo giù tutto quello che dobbiamo fare è trovare un negativo valore esadecimale che termina nel FFFFFFe dal momento che i valori esadecimali negativo deve essere nel formato di FFFFXXXXXX(in modo tale che Xè una valida esadecimale) il conto alla rovescia da FFFFFFFFFF( -1) a FFFF000001(-16777215 )

Sapendo questo possiamo generalizzare che la formula

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

Usando questo, alcune conversioni utili sono

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

Buono a sapersi cosa stava succedendo lì, l'ho appena scoperto per caso in quella domanda - ma questa chiara spiegazione mostra esattamente come funziona. Un'altra cosa da tenere a mente è che alcuni colori chiave possono essere ridotti con operatori matematici; rgbWhite= 2^24-1anche se potrebbe eventualmente essere ulteriormente ridotto se perdi -1 per arrivare più o meno lì
Greedo

1
In effetti, ecco un elenco di colori con le loro rappresentazioni matematiche, che sono più brevi delle versioni decimali positive o negative: &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 non necessariamente completo, ma penso di aver fatto un lavoro abbastanza approfondito
Greedo

1

Omettere il terminale "quando si stampa su Finestra immediata

Data la funzione di seguito, che deve essere utilizzata nella finestra di debug

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

Il Terminale "può essere lasciato cadere per -1 byte, lasciando la stringa chiusa e il programma deve eseguire lo stesso, senza errori

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

Ancora più sorprendente di questo è che questo può essere fatto all'interno di subroutine completamente definite.

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

La subroutine sopra viene eseguita come previsto e viene eseguita automaticamente

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

1

Usa le variabili Truthy e Falsey nei condizionali

A volte chiamato conversione di tipo implicita - direttamente utilizzando un tipo di numero in una If, [IF(...)]o IIf(...)dichiarazione, utilizzando l'truthy e Falsey natura di tale numero può assolutamente risparmiare alcuni byte.

In VBA, qualsiasi variabile di tipo numerico diversa da zero è considerata come vera (e quindi zero 0, è l'unico valore falso) e quindi

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

può essere condensato a

If B Then C=B Else C=D

e oltre a

C=IIf(B,B,D)

1

Fogli indirizzo per nome

Invece di indirizzare un WorkSheetoggetto chiamando

Application.ActiveSheet
''  Or 
ActiveSheet   

Uno può usare

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

O più preferibilmente si può accedere direttamente all'oggetto e utilizzarlo

Sheet1

1

Exponentiation e LongLongs in VBA a 64 bit

La forma generale di esponenziazione,

A to the power of B

Può essere rappresentato come in VBA come

A^B 

Ma solo nelle installazioni a 32 bit di Office , nelle installazioni a 64 bit di Office, il modo più breve che puoi rappresentare senza errori è

A ^B

Questo perché nelle versioni a 64 bit di VBA ^funge sia da LongLongcarattere di dichiarazione esponenziale che da carattere di dichiarazione . Ciò significa che può sorgere una sintassi piuttosto strana ma valida come

a^=2^^63^-1^

che assegna una variabile aper contenere il valore massimo di aLonglong


1

Comprimi array di byte come stringa

Per le sfide che richiedono che la soluzione contenga dati costanti, può essere utile comprimere tali dati come una singola stringa e quindi iterare attraverso la stringa per recuperare i dati.

In VBA, qualsiasi valore di byte può essere convertito direttamente in un carattere con

Chr(byteVal)

E un valore longo integerpuò essere convertito in due caratteri con

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

Quindi per un bytearray un algoritmo di compressione sarebbe simile

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$

Notando che la Select Casesezione è implementata a causa dei caratteri che non possono essere memorizzati come letterali nella stringa.

Dalla stringa risultante, che avrà un aspetto simile

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

I dati possono quindi essere estratti utilizzando le funzioni Asce Mid, ad es

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

1

Utilizzare costanti improprie

VBA consente, in alcuni casi, l'uso di costanti non elencate o improprie in espressioni che richiedono valori costanti. Si tratta spesso di valori legacy e di lunghezza inferiore rispetto ai valori corretti.

Ad esempio, i valori seguenti possono essere utilizzati quando si lascia un valore trattenuto dalla rng.HorizantalAlignmentproprietà.

ImpropriocorrettoCostante GeneralexlHAlign  Costante11xlGeneralxlHAlignGeneral2-4131xlLeftxlHAlignLeft3-4108xlCenterxlHAlignCenter4-4152xlRightxlHAlignRight55xlFillxlHAlignFill6-4130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection8-4117xlDistributedxlHAlignDistributed

Ciò significa, ad esempio, che l'impostazione di una cella su cui centrare il testo

rng.HorizantalAlignment=-4108

può essere ridotto a

rng.HorizantalAlignment=3

sostituendo il valore costante improprio 3per il valore corretto -4108. Si noti che se si recupera il rng.HorizantalAlignmentvalore della proprietà, verrà restituito il valore corretto. In questo caso, sarebbe -4108.


1

In Excel, crea matrici numeriche raggruppando gli intervalli

Quando un insieme monodimensionale costante di valori numerici di lunghezza mista, Sè necessario, deve essere più efficiente usare la [{...}]notazione per dichiarare un intervallo e poi forzarlo in una matrice numerica piuttosto che usare la Split(String)notazione o simile.

Utilizzando questo metodo, un cambiamento di Δconteggio byte=-5 byte devono essere maturati per tutti S.

Esempio

Per esempio,

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

può essere scritto come

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

Vale inoltre la pena notare che sebbene questo metodo non consenta l'indicizzazione diretta, consente l'iterazione direttamente sul ciclo for direttamente, ovvero

For Each s In[{1,3,5,7,9,2,4,6,8}]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.