Conseils pour jouer au golf en VBA

16

Semblable à ceci , ceci et cette question ...

Quels conseils généraux avez-vous pour jouer au golf VBA ? Je recherche des idées qui peuvent être appliquées aux problèmes de golf de code en général qui sont au moins quelque peu spécifiques VBA(par exemple, "supprimer les commentaires" n'est pas une réponse). Veuillez poster un pourboire par réponse.

Bien que j'ai travaillé avec d'autres langues, je suis le plus fort VBAet je ne vois pas beaucoup de golfeurs utiliser VBAsur ce site.

Gaffi
la source
Converti en wiki communautaire conformément à la politique.
dmckee --- chaton ex-modérateur
Désolé ce n'était pas automatique de ma part!
Gaffi
Aucune difficulté. En fait, ils ont pris le pouvoir de faire des questions CW aux utilisateurs (vous pouvez toujours faire des réponses, je pense). Vous pouvez signaler l'attention du modérateur, mais aussi peu d'activité que CodeGolf obtient, ce n'est guère nécessaire.
dmckee --- chaton ex-modérateur
2
VBA est un langage relativement verbeux avec peu de raccourcis syntaxiques. Si vous recherchez le meilleur score, VBA n'est peut-être pas un bon choix. Si vous cherchez à perfectionner vos compétences, plus de pouvoir pour vous.
M. Llama
2
@GigaWatt Honing my skills it is. En fait, depuis que je joue avec différents défis, j'ai déjà pris quelques nouvelles astuces pour travailler avec VBA! Je ne m'attends pas à gagner de vrais défis de code-golf avec VBA, mais c'est une bonne pratique. :-)
Gaffi

Réponses:

8

Exploitez la ByRefvaleur par défaut lors de l'appel de sous-marins

Il est parfois possible d'utiliser un Subappel à la place d'un Functionpour enregistrer quelques caractères supplémentaires ...

Ce ( 87 caractères)

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

peut être retravaillé pour ( 73 caractères):

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

Notez que cela ne bouclera PAS indéfiniment, bien qu'il semble que vous ne réaffectiez jamais bla valeur de

Ce qui précède n'utilise pas de Function appel, mais exploite à la place la fonctionnalité ByRef("Par référence") de l' Subappel. Cela signifie que l'argument passé est la même variable que dans la fonction appelante (par opposition à unByVal "By Value", qui est une copie). Toutes les modifications apportées à la variable transmise se traduiront par la fonction appelante.

Par défaut, tous les arguments ByRef, il n'est donc pas nécessaire d'utiliser des caractères pour le définir.

L'exemple ci-dessus peut ne pas se traduire parfaitement pour vous, selon la valeur de retour de votre fonction. (c'est-à-dire renvoyer un type de données différent de ce qui est transmis), mais cela permet également d'obtenir une valeur de retour tout en modifiant votre variable d'origine.

Par exemple:

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
Gaffi
la source
7

Écrivez et exécutez le code VBA dans la fenêtre Exécution

La fenêtre immédiate évalue toute instruction exécutable VBA valide. Entrez simplement une instruction dans la fenêtre immédiate comme vous le feriez dans l'éditeur de code. Il exécute rapidement le code VBA et peut enregistrer de nombreux caractères supplémentaires car:

  1. Mettre le point d'interrogation (?) Au début de l'instruction indique à la fenêtre immédiate d'afficher le résultat de votre code.

enter image description here

  1. Vous n'avez pas besoin d'utiliser un Sub et un End Sub dans votre code.

enter image description here


Voici l'exemple de code VBA dans la fenêtre immédiate pour répondre au message de PPCG avec le : La lettre A sans A

?Chr(88-23);

répondu par Joffan .


Images de crédit: Excel Campus

Anastasiya-Romanova 秀
la source
1
Mais qui utilise un environnement REPL? Cela signifie que ce n'est qu'un extrait de code, pas un programme ou une fonction
caird coinheringaahing
Je pense qu'un autre exemple à ajouter peut être que vous pouvez également créer des variables en ligne; ex. a="value":?adéfinit d'abord la valeur de a, puis l'imprime.
Greedo
6

Vérifications conditionnelles avant la boucle

Certains contrôles conditionnels sont redondants lorsqu'ils sont utilisés conjointement avec des boucles. Par exemple, unFor boucle ne sera pas traitée si la condition de démarrage est en dehors de la portée de la condition en cours d'exécution.

En d'autres termes, ceci ( 49 caractères):

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

Peut être transformé en ceci ( 24 caractères):

For C = A To A + B ' if B is 0 or less, then the code continues past Next, unabated.
'...
Next
Gaffi
la source
Le commentaire en bas est incorrect. Si B = 0, alors la boucle sera entrée. pastebin.com/97MBB7hq
QHarr
5

Déclaration variable

Dans la plupart des cas dans VBA, vous pouvez laisser de côté Option Explicit(souvent omis par défaut de toute façon) et ignorer Dimun grand nombre de vos variables.

Ce faisant, cela ( 96 caractères ):

Option Explicit

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

Devient ceci ( 46 caractères):

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

Si vous devez utiliser certains objets (par exemple, des tableaux), vous devrez peut-être toujours utiliser Dimcette variable.

Gaffi
la source
Attendez une seconde, vous avez accepté votre propre réponse à votre question. Pas cool, mec.
Taylor Scott
1
@TaylorScott C'est un article wiki - pas de points, et dans ce cas, il n'y a pas une seule meilleure réponse. :) J'accepte la réponse il y a environ 5 ans pour éviter d'avoir un indicateur dans ma liste de questions.
Gaffi
1
@TaylorScott aussi si vous acceptez votre propre réponse, vous n'obtenez pas +15 ou +2 (pour l'acceptation)
caird coinheringaahing
5

Evaluate() Et []

Comme cela a été souligné précédemment, les appels de plage codés en dur peuvent être réduits en utilisant les crochets [A1] notation . Cependant, il a beaucoup plus d'utilisations que cela.

Selon la documentation MSDN , la Application.Evaluate()méthode prend un seul argument, qui est unName , tel que défini par la convention de dénomination de Microsoft Excel.

NB [string]est un raccourci pour Evaluate("string")(notez les ""marques vocales indiquant le type de données de chaîne), bien qu'il y ait quelques différences importantes qui sont couvertes à la fin.

Alors qu'est-ce que tout cela signifie en termes d'utilisation?

Essentiellement, [some cell formula here]représente une cellule dans une feuille de calcul Excel, et vous pouvez y mettre à peu près n'importe quoi et en retirer tout ce que vous pourriez avec une cellule normale

Que se passe-t-il

En résumé, avec des exemples

  • Références de style A1. Toutes les références sont considérées comme des références absolues.
    • [B7] renvoie une référence à cette cellule
    • Les références étant absolues, ?[B7].Addressrenvoie"B$7$"
  • Plages Vous pouvez utiliser les opérateurs de plage, d'intersection et d'union (deux points, espace et virgule, respectivement) avec des références.
    • [A1:B5]renvoie une référence de plage à A1:B5(Plage)
    • [A1:B5 A3:D7]renvoie une référence de plage à A3:B5(Intersect)
    • [A1:B5,C1:D5]renvoie une référence de plage à A1:D5(techniquement A1:B5,C1:D5) (Union)
  • Noms définis
    • Défini par l'utilisateur, par exemple en se [myRange]référant à A1: G5
    • Automatique, comme les noms de table [Table1](peut-être moins utile pour codegolf)
    • Tout ce que vous pouvez trouver dans le menu [Formulas]>[Name Manager]
  • Formules
    • Très utile ; toute formule qui peut aller dans une cellule peut aller Evaluate()ou[]
    • [SUM(1,A1:B5,myRange)]renvoie une somme arithmétique de valeurs dans les plages myRange fait référence ici à un nom de classeur et non à une variable VBA
    • [IF(A1=1,"true","false")](1 octet plus court que l'équivalent vba Iif([A1]=1,"true","false"))
    • Formules de tableau [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]- joint toutes les chaînes de la plage dont la longueur est supérieure à 2 avec un espace
  • Références externes
    • Vous pouvez utiliser l' !opérateur pour faire référence à une cellule ou à un nom défini dans un autre classeur
    • [[BOOK1]Sheet1!A1]renvoie une référence de plage à A1 dans BOOK1 ou ['[MY WORKBOOK.XLSM]Sheet1!'A1]pour la même chose dansMY WORKBOOK
    • Notez le 'pour les classeurs avec des espaces dans leurs noms et le manque d'extension pour les classeurs nommés par défaut ( BOOK+n)
  • Objets de graphique (voir l'article MSDN)

NB J'ai posé une question sur SO pour cette info, alors jetez un œil pour une meilleure explication

Ce qui sort

Semblable à ce qui entre, ce qui sort inclut tout ce qu'une cellule de feuille de calcul peut renvoyer. Ce sont les types de données Excel standard (et leurs équivalents VBA):

  • Logique ( Boolean)
  • Texte ( String)
  • Numérique ( Double)
  • Error ( Variant/Error) (ce sont des erreurs insécables, c'est-à-dire qu'elles n'interrompent pas l'exécution du code, ?[1/0]s'exécutent correctement)

Mais il y a quelques choses qui peuvent être retournées que les cellules ne peuvent pas:

  • Référence de plage ( Range) (voir les sections ci-dessus)
  • Tableaux ( Variant())

Tableaux

Comme cela a été montré, []peut être utilisé pour évaluer des formules matricielles qui renvoient l'un des types de données Excel standard; par exemple, [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]qui revient Text. Cependant, il Evaluatepeut également renvoyer des tableaux de Varianttype. Celles-ci peuvent être

Hardcoded:

[{1,2;3,4}]- sort un tableau 2D: ,est le séparateur de colonnes, ;sépare les lignes. Peut sortir un tableau 1D

Formules matricielles:

[ROW(A1:A5)]- génère un tableau 2D{1,2,3,4,5} , c'est-à-dire que (2,1) est le deuxième élément (pourtant certaines fonctions produisent des tableaux 1D)

  • Pour une raison quelconque, certaines fonctions ne renvoient pas de tableaux par défaut

[LEN(A1:A5)] affiche uniquement la longueur du texte dans la 1ère cellule d'une plage

  • Cependant, ceux-ci peuvent être contraints de donner des tableaux

Split([CONCAT(" "&LEN(A1:A5))]) donne un tableau 1D 0 à 5, où le premier élément est vide

[INDEX(LEN(A1:A5),)]est une autre solution de contournement, vous devez essentiellement utiliser une fonction de gestion de tableau pour obtenir le comportement de retour de tableau souhaité, similaire à l'ajout d'un vide RAND()de sens pour rendre vos formules de feuille de calcul volatiles.

  • J'ai posé une question sur SO pour essayer d'obtenir de meilleures informations à ce sujet, veuillez modifier / commenter avec de meilleures options si vous les trouvez

Evaluate() contre []

Il y a quelques différences entre Evaluate()et []être conscient de

  1. Strings vs hardcoded
    • Peut-être la différence la plus importante, Evaluate prend une entrée de chaîne où [] nécessitait une entrée codée en dur
    • Cela signifie que votre code peut construire la chaîne avec des variables , par exemple Evaluate("SUM(B1,1,"&v &",2)")résumerais [B1], 1, 2et variablev
  2. Tableaux

    Lors du retour d'un tableau, seul Evaluate peut être utilisé avec un index de tableau, donc

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

    est équivalent à

    i=[ROW(A1:A5)]:v=i(1,1) ''#23 bytes
Greedo
la source
Désolé pour le poste gigantesque, si quelqu'un pense qu'il peut rendre les zones plus concises / si vous avez des conseils à ajouter, n'hésitez pas. De plus, bien que j'aie fait des recherches sur cela, une bonne partie a été trouvée en expérimentant en VBA, donc si vous repérez des erreurs de sentiment qu'il manque quelque chose, n'hésitez pas à commenter / éditer en conséquence!
Greedo
1
En fait, la dernière section sur les tableaux est un peu décalée - elle peut être utilisée dans la fenêtre immédiatei=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott
@TaylorScott Donc, vous le pouviez, je n'étais pas du tout au courant que vous pouviez définir / conserver des valeurs dans des variables qui n'étaient pas déjà définies, mais je suppose que c'est parce que j'arrive toujours à maîtriser les 1-liners de la fenêtre immédiate. Ont mis à jour en conséquence
Greedo
Est-ce que cela fonctionne avec Match? J'ai essayé, mais cela renvoie toujours des erreurs. Je passais un tableau au lieu d'une plage, cependant.
seadoggie01
5

Combiner des Nextdéclarations

Next:Next:Next

Peut être condensé jusqu'à

Next k,j,i

où les itérateurs pour les Forboucles sont i, jet k- dans cet ordre.

Par exemple ci-dessous (69 octets)

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

Peut être condensé jusqu'à 65 octets

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

Et en ce qui concerne la façon dont cela affecte la mise en forme et l'indentation, je pense que la meilleure approche pour gérer cela est d'aligner la prochaine déclaration avec la plus externe pour la déclaration. Par exemple.

For i=0To[A1]
    For j=0To[B1]
        For k=0To[C1]
            Debug.?i;j;k
Next k,j,i
Taylor Scott
la source
4

Réduire les Ifdéclarations

Lors de l'affectation d'une variable à l'aide d'un conditionnel If ... Then ... Else vérification , vous pouvez réduire la quantité de code utilisée en éliminant le End Ifen mettant la vérification entière sur une seule ligne.

Par exemple, ceci ( 37 caractères):

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

Peut être réduit à cela ( 30 caractères)

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

Si vous avez plusieurs conditions conditionnelles imbriquées, vous pouvez également les réduire de cette façon:

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

Noter la : vous permet d'ajouter plus d'une ligne / commande dans un Ifbloc.

Dans des cas simples comme celui-ci, vous pouvez généralement supprimer le Elseen définissant la variable avant le Ifcontrôle ( 25 caractères):

c = a
If a < b Then c = b

Encore mieux, ce qui précède peut être encore réduit à cela en utilisant la IIf()fonction ( 20 caractères):

c = IIf(a < b, b, a)
Gaffi
la source
3

Réduire Range("A1") et aimer les appels

Range("A1").Value(17 octets) et le plus simple Range("A1")(11 octets) peuvent être réduits à [A1](4 octets)

Taylor Scott
la source
2
Ou en général, l'utilisation de []pour remplacer Evaluate()dans VBA est beaucoup plus polyvalente que les appels de gamme. Par exemple, vous pouvez l'utiliser pour remplacer WorksheetFunction.FuncName(args)par juste [FuncName(args)], comme ?[SUMPRODUCT({1,3,5},{2,7,-1})]ou le très utile [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo
Greedo, c'est une fonctionnalité incroyablement importante dont je ne savais pas que vous devriez l'ajouter comme sa propre réponse.
Taylor Scott
1
Bien sûr, je vais écrire quelque chose sous peu. Oui Evaluate("str")ou la sténographie [str]est très puissante en VBA, je ne l'ai découvert que récemment, et je suppose que cela sera également utile pour le golf!
Greedo
Très utile, assez pour que je revienne à travers mes réponses pour voir si je peux laisser tomber mon bytecount sur tout à cause de cela
Taylor Scott
3

Supprimer les espaces

VBA se formatera automatiquement pour ajouter beaucoup d'espacement dont il n'a pas réellement besoin. Il y a une réponse sur meta qui a beaucoup de sens pour moi pourquoi nous pouvons réduire les octets ajoutés par formatage automatique. Il est cependant important de toujours vérifier que vous n'en avez pas trop retiré. Par exemple, voici une de mes réponses qui a été réduite de près de 22% simplement en supprimant des espaces:

Version originale: (188 octets)

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

Version réduite: (146 octets)

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

Si vous copiez / collez la version réduite dans VBA, elle se développera automatiquement dans l'original. Vous pouvez jouer avec l'endroit où il est valide pour supprimer des espaces. Ceux que j'ai trouvés jusqu'à présent semblent tous suivre le modèle dans lequel VBA attend qu'une certaine commande apparaisse car, sans elle, ce n'est pas du code valide. En voici quelques-unes que j'ai trouvées jusqu'à présent:

  • Avant et après toute opération mathématique: +-=/*^ etc.
  • Avant Toet Stepdans une Fordéclaration:For x=-3To 3Step 0.05
  • En fait, avant tout mot réservé ( To, &, Then, etc.) si elle est précédée d'un littéral comme un numéro, ), ?,% , etc.
  • Après le & combinaison de chaînes:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • Après les appels de fonction: If s=StrReverse(s)Then
  • Dans les appels de fonction: Replace(Space(28)," ",0)
Ingénieur Toast
la source
Quelle est la règle sur l'ajout de caractères non-espace via la mise en forme automatique. Quelque chose comme ?vs Printje vois est acceptable, mais mettre à la déclaration de type comme &immédiatement après une variable Debug.?a&"z"donne par exemple Debug.Print a&; "z". Le ;caractère ajouté est essentiel pour l'exécution du code - est-ce toujours autorisé?
Greedo
2
@Greedo Je le vois comme la méta-réponse l'a décrit: si vous pouvez le copier / coller dans l'éditeur et que le code s'exécutera, c'est OK. IE, si VBA ajoute automatiquement le caractère lorsque vous collez le code, alors c'est OK.
Engineer Toast
1
@EngineerToast, vous pouvez supprimer un octet de plus de votre exemple: If i=1 Then peut devenirIf i=1Then parce que, en règle générale , un mot réservé qui suit un littéral, que ce soit un numéro, ), ?, %, .. etc, n'a pas besoin d'être séparés par un espace
Taylor Scott
1
@EngineerToast, vous pouvez également supprimer un octet de votre troisième puce car vous pouvez supprimer les espaces entre un )(ou tout autre littéral non numérique) et&
Taylor Scott
3

Préparez-vous au Pixel Art

Le pixel art est de loin l'un des domaines les plus forts d'Excel, car il n'est pas nécessaire de construire un canevas, car il est déjà là pour vous - tout ce que vous devez faire est de faire de petits ajustements

1) Rendre les cellules carrées

Cells.RowHeight=48

ou, alternativement, pour 1 octet de plus, mais beaucoup plus facile à utiliser

Cells.ColumnWidth=2

2) Colorez la plage nécessaire

Tout Rangeobjet peut être coloré en appelant

`MyRangeObj`.Interior.Color=`ColorValue`

Remarque: cela peut et doit être combiné avec d'autres astuces notées sur ce wiki, telles que le référencement de plages par l'utilisation de la []notation (par exemple [A1:R5,D6]) sur l'utilisation d'un Cells(r,c)ou d'unRange(cellAddress) appel. De plus, comme indiqué sur ce wiki, cela peut être combiné avec une valeur de couleur négative pour réduire la taille des références de couleur

Références rapides

Référence de plage

Cellule A1 peut être référencée de l'une des manières suivantes

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

et la gamme A1:D4 peut être référencée de l'une des manières suivantes

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

Référence de couleur

Black  0
White  -1
Red    255
Aqua   -256
Taylor Scott
la source
3

Simplifiez les fonctions intégrées

Lorsque vous utilisez fréquemment certaines fonctions, réaffectez-les à une fonction définie par l'utilisateur.

Le code suivant ( 127 caractères) peut être réduit de:

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 caractères):

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

En combinant cela avec l' astuce ByRef , vous pouvez enregistrer encore plus de caractères (jusqu'à 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

Faites-le judicieusement, car VBA prend beaucoup de caractères pour définir un Function. Le deuxième bloc de code serait en fait plus grand que le premier avec un nombre moindre d' Format()appels.

Gaffi
la source
2
dans le dernier, vous n'avez pas besoin de l'appel d'affectation, ce qui signifie qu'il a = f(w)peut être réduit àf w
Taylor Scott
3

STDIN et STDOUT

Entrée dans les Subroutines et les Functions via des variables d'entrée

Public Sub A(ByRef B as String)

Peut être réduit à

Sub a(b$) 

Le PublicetByRef appels sont la valeur par défaut pour VBA et donc implicites, et peuvent (presque) toujours être supprimés.

Le type littéral $oblige bà être du typeString .

Littéraux d'autres types

  • ! Célibataire
  • @ Devise
  • # Double
  • % Entier
  • $ Chaîne
  • & Longue
  • ^ LongLong (64 bits uniquement)

En outre, il est généralement admis que vous pouvez laisser la variable d'entrée comme type par défaut Variantet laisser toute erreur basée sur le type non gérée. Par exemple. Sub E(F)dans lequel Fon s'attend à être de type Boolean[](qui serait passé à la routine commeE Array(True, False, False) )

Saisie des Subroutines et des fonctions de fenêtre immédiate viaCells

VBA n'a pas de console entièrement fonctionnelle et n'a donc pas de STDIN officiel , et permet donc à certains lecture avec l' entrée de passage.

Dans Excel, il est généralement accepté de prendre des données à partir d'une cellule ou d'une plage de cellules, ce qui peut se faire comme

s=[A1]

qui met implicitement le .valuede la cellule [A1](qui peut également être référencé comme cells(1,1)ourange("A1")

Exemple de problème: afficher l'entrée dans une boîte de message

Via Subroutine Sub A:msgbox[A1]:End Sub

Via la fonction de fenêtre Immediates msgbox[A1]

Saisie via des arguments de compilation conditionnelle

Les projets VBA prennent en charge la prise d'arguments à partir de la ligne de commande ou via les propriétés VBAProject (affichage via l'explorateur de projet -> [Votre projet VBA] - (clic droit) -> Propriétés VBAProject -> Arguments de compilation conditionnelle)

Ceci est largement utile pour les défis de code d'erreur

Étant donné l'argument de compilation conditionnelle n=[some_value], cela permet d'exécuter du code qui produira un code d'erreur, basé sur la valeur de n. notez que cela nécessite l'ajout de 2 octets à votre code pour la n=section des arguments de compilation conditionnelle du volet Propriétés de VBAProject.

Exemple de code

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

Sortie via la valeur de fonction

Pas grand-chose à dire ici, la forme générale de la citation ci-dessous est à peu près aussi compacte que possible.

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

REMARQUE: dans la grande majorité des cas, il est préférable de convertir la méthode en sous-programme et de la sortir vers la fenêtre VBE Immediates (voir ci-dessous)

Sortie des Subroutines et des Functions via la fenêtre VBE Immediates

La sortie vers la fenêtre VBE Immediates (AKA la fenêtre de débogage VBE) est une méthode de sortie courante pour VBA pour les défis basés sur du texte, cependant, il est important de se rappeler que l' Debug.Print "Text"appel peut être considérablement joué.

Debug.Print "Text"

est fonctionnellement identique à

Debug.?"Text"

comme ?formats automatiques pour Print.

Sortie à partir de Subroutines et de fonctions de fenêtre VBE Immediates via d'autres méthodes

En de rares occasions, lorsque la situation est parfaite, vous pouvez prendre des données à partir de certaines des entrées les plus triviales disponibles pour VBA, telles que le réglage de la taille de police, le sélecteur de police et le zoom. (Par exemple, émulation du sélecteur de taille de police Word )

Taylor Scott
la source
2

Note rapide sur le formatage

Parce que StackExchange utilise Markdown et Prettify.js il est possible d'ajouter un indicateur de langue à vos réponses de codage, ce qui les rend généralement plus professionnelles. Bien que je ne puisse pas garantir que cela vous rendra meilleur au golf à VBA, je peux garantir que cela vous fera ressembler à vous.

L'ajout de l'un des drapeaux ci-dessous transformera

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

à

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

Balises de langue VBA

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

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

Remarque: ce dernier transforme tous les segments de code dans votre réponse, tandis que le précédent transforme uniquement les segments de code immédiatement suivants

Taylor Scott
la source
lang-vbhein? - Étrange que ça formate mieux que lang-vbapour les réponses vba.
Greedo
1
@Greedo, c'est parce que tandis que lang-vbafournira la surbrillance, c'est en fait juste la surbrillance par défaut. Apparemment, VBA n'a pas été réellement implémenté dans Prettify.js, nous devrons donc nous en tenir à la mise en évidence de VB
Taylor Scott
2

Plusieurs If .. ThenContrôles

Comme dans d'autres langues, plusieurs Ifcontrôles peuvent généralement être combinés en une seule ligne, permettant l'utilisation de And/ Or(c'est &&- ||à- dire / en C et autres), qui en VBA remplace à la fois a Thenet an End If.

Par exemple, avec un conditionnel imbriqué ( 93 caractères):

'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

peut devenir ( 69 caractères):

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

Cela fonctionne également avec les conditions non imbriquées.

Considérez ( 84 caractères):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Cela peut devenir ( 51 caractères):

If a = b Or c = b Then            
    d = 0
End If
Gaffi
la source
1
dans les instructions If - then, la partie "End - if" est facultative à condition que vous écriviez le code sur une seule ligne.
Stupid_Intern
@newguy Correct. Voir aussi cette autre réponse: codegolf.stackexchange.com/a/5788/3862
Gaffi
La déclaration ci-dessus peut être condensée plus loind=iif(a=b or c=b,0,d)
Taylor Scott
2

Fin des Forboucles

Lorsque vous utilisez des Forboucles, unNext ligne n'a pas besoin d'un nom de variable (bien qu'il soit probablement préférable de l'utiliser dans le codage normal).

Donc,

For Variable = 1 to 100
    'Do stuff
Next Variable

peut être raccourci à:

For Variable = 1 to 100
    'Do stuff
Next

(Les économies dépendent du nom de votre variable, mais si vous jouez au golf, c'est probablement juste 1 caractère + 1 espace.)

Gaffi
la source
1
2 personnages, n'oubliez pas de compter l'espace!
11684
Il m'arrive de ne presque jamais identifier la variable, même en code normal!
dnep
2

Fractionner une chaîne en un tableau de caractères

Parfois, il peut être utile de séparer une chaîne en caractères individuels, mais cela peut prendre un peu de code pour le faire manuellement dans 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

Au lieu de cela, vous pouvez utiliser une seule ligne, une chaîne de fonctions relativement minimale pour faire le travail:

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

Cela affectera votre chaîne sau Varianttableau a. Soyez prudent, cependant, car le dernier élément du tableau sera une chaîne vide ( ""), qui devra être gérée de manière appropriée.

Voici comment cela fonctionne: La StrConvfonction convertit a Stringdans un autre format que vous spécifiez. Dans ce cas, 64 = vbUnicode, il se convertit donc au format unicode. Lorsqu'il s'agit de chaînes ASCII simples, le résultat est un caractère nul (pas une chaîne vide "") inséré après chaque caractère.

Ce qui suit Splitconvertira ensuite le résultat Stringen un tableau, en utilisant le caractère nul Chr(0)comme délimiteur.

Il est important de noter que ce Chr(0)n'est pas la même chose que la chaîne vide "", et l'utilisation Splitde ""on ne retournera pas le tableau auquel vous vous attendez. La même chose est également vraie pour vbNullString(mais si vous jouez au golf, alors pourquoi utiliseriez-vous une telle constante verbeuse en premier lieu?).

Gaffi
la source
Vous devez mentionner que le tableau résultant a une chaîne vide supplémentaire à la fin.
Howard
@Howard Oui, je devrais. C'était dans ma tête pendant que j'écrivais ça, ça a dû me fuir l'esprit.
Gaffi
2

Utilisation With(Parfois! Voir note de bas de page)

En utilisant le With instruction peut réduire considérablement la taille de votre code si vous utilisez plusieurs objets à plusieurs reprises.

c'est-à-dire ceci ( 80 caractères):

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

peut être codé comme ( 79 caractères):

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

Ce qui précède n'est même pas le meilleur des cas. Si vous utilisez quoi que ce soit avec Application, par exemple Excel.Applicationdepuis Access, l'amélioration sera beaucoup plus importante.


* Selon la situation, Withpeut ou peut ne pas être plus efficace que cela ( 64 caractères):

Set i = foo.bar.object
x = i.a.value
y = i.b.value
z = i.c.value
Gaffi
la source
2

Boucles infinies

Envisager de remplacer

Do While a<b
'...
Loop

ou

Do Until a=b
'...
Loop

avec le nombre d'octets archaïque mais inférieur

While a<b
'...
Wend

Si vous devez quitter a Subou Functionprématurément, au lieu deExit ...

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

considérer End

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

Notez que Endstoppe toute exécution de code et efface toutes les variables globales, donc utilisez-les judicieusement

Greedo
la source
Vous devriez envisager de réécrire la dernière section ( Foret End) pour refléter que le cas 100ne sera jamais satisfait et ajouter un octet inutile
Taylor Scott
En outre, bien que cela soit très lisible, vous pouvez envisager de supprimer l'espace blanc pour mieux montrer les avantages possibles de ces méthodes (il est toujours bon d'abuser de la mise en forme automatique dans VBA pour le codage)
Taylor Scott
2

Utilisez Spc(n)plus Space(n), [Rept(" ",n)]ouString(n," ")

Lorsque vous essayez d'insérer plusieurs espaces de longueur n, utilisez

Spc(n)              ''  6  bytes

plus de

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

Remarque: je ne sais pas pourquoi, mais il semble que vous ne pouvez pas affecter la sortie de Spc(n)à une variable, et qu'elle doit plutôt être imprimée directement - donc dans certains cas, Space(n)c'est toujours la meilleure façon de procéder.

Taylor Scott
la source
2

Réduction Debug.Printet Printappels

Debug.Print [some value] 

(12 octets; notez l'espace de fin) peut être réduit à

Debug.?[some value]

(7 octets; notez le manque d'espace de fin).

De même,

Print 

(6 octets) peut être réduit à

?

(1 octet).

De plus, lorsque vous travaillez dans le contexte d'une fonction de fenêtre immédiate VBE anonyme, l' Debuginstruction peut être entièrement supprimée et l'impression à la place dans la fenêtre immédiate VBE via ?peut être supposée être STDIN / STDOUT

Caractères spéciaux

Lors de l'impression de chaînes, vous pouvez également utiliser des caractères spéciaux à la place de &. Ceux-ci permettent des formats alternatifs dans ce qui est imprimé ou la suppression des espaces

Pour joindre des chaînes variables, au lieu de

Debug.Print s1 &s2

Vous pouvez utiliser un point-virgule ;

Debug.?s1;s2

Ce point-virgule est le comportement par défaut pour les chaînes consécutives, tant qu'il n'y a pas d'ambiguïté. Donc, celles-ci sont valides:

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

Mais non

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

Notez que a; à la fin d'une ligne supprime une nouvelle ligne, car les nouvelles lignes sont ajoutées par défaut après chaque impression. Le comptage des octets retournés par le code VBA est en débat

Pour rejoindre un onglet, utilisez une virgule ,(en fait 14 espaces, mais selon)

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

Enfin, vous pouvez utiliser des déclarations de type pour joindre des chaînes au lieu de;, chacune ayant son propre léger effet sur la mise en forme. Pour tout ce qui suit a = 3.14159est la première ligne

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
Taylor Scott
la source
2

Utilisez un assistant SubpourPrint

Si le code nécessite l'utilisation de plus de six Debug.? instructions, vous pouvez réduire les octets en remplaçant tous les débogages. lignes avec un appel à un Sub comme celui ci-dessous. Pour imprimer une ligne vierge, vous devez appeler p ""car un paramètre est requis.

Sub p(m)
Debug.?m
End Sub
Ben
la source
1
Pour imprimer une nouvelle ligne que vous avez seulement besoin p""ou si elle peut être unterminated, p". Cependant, dans la grande majorité des cas où cela peut s'appliquer, il est plus logique d'utiliser une variable de chaîne et de n'imprimer la variable de chaîne qu'à la fin.
Taylor Scott
1

Utiliser Array() Choose()au lieu de SelectouIf...Then

Lorsque vous affectez une variable en fonction de la valeur d'une autre variable, il est logique d'écrire les étapes avec des If...Thencontrôles, comme ceci:

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

Cependant, cela peut prendre beaucoup d'espace de code s'il y a plus d'une ou deux variables à vérifier (il y a quand même généralement de meilleures façons de le faire).

Au lieu de cela, l' Select Caseinstruction permet de réduire la taille des vérifications en regroupant tout dans un bloc, comme suit:

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

Cela peut conduire à un code beaucoup plus petit, mais pour des cas très simples comme celui-ci, il existe une méthode encore plus efficace: Choose()cette fonction sélectionne une valeur dans une liste, en fonction de la valeur qui lui est transmise.

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

L'option à sélectionner ( adans ce cas) est une valeur entière passée comme premier argument. Tous les arguments suivants sont les valeurs à choisir (indexées 1, comme la plupart des VBA). Les valeurs peuvent être de n'importe quel type de données tant qu'elles correspondent à la variable définie (c'est-à-dire que les objets ne fonctionnent pas sans le Setmot - clé) et peuvent même être des expressions ou des fonctions.

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

Une option supplémentaire consiste à utiliser la Arrayfonction pour obtenir le même effet tout en enregistrant un autre caractère:

b = Array(5 + 4, String(7,"?"))(a)
Gaffi
la source
An interesting and possibly very beneficial use for golfing is to use this in conjunction with an IIf() or another 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

Bit-Shifted RGB Values

Because of the way that Excel handles colors, (unsigned, 6-character hexadecimal integer) you can make use of negatively signed integers, of which excel will only use the right 6 bytes to assign a color value

This is a bit confusing so some examples are provided below

Lets say you want to use the color white, which is stored as

rgbWhite

and is equivalent to

&HFFFFFF ''#value: 16777215

to golf this down all we need to do is find a negative hexadecimal value which terminates in FFFFFF and since negative Hex values in must be in the format of FFFFXXXXXX (such that X is a valid hexadecimal) counting down from FFFFFFFFFF (-1) to FFFF000001 (-16777215)

Knowing this we can generalize that the formula

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

Using this, some useful conversions are

rgbWhite = &HFFFFFF = -1 
rgbAqua  = &HFFFF00 = -256
16747627 = &HFF8C6B = -29589
Taylor Scott
la source
Good to know what was going on there, I just discovered it by accident in that question - but this clear explanation shows exactly how it works. Another thing to bear in mind is that certain key colours can be reduced with mathematical operators; rgbWhite=2^24-1 although could possibly be reduced further if you miss off the -1 to get roughly there
Greedo
1
In fact, here is a list of colours with their mathematical representations, which are shorter than either the positive or negative decimal versions: &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 n.b. not necessarily complete, but I think I did a fairly thorough job
Greedo
1

Omit terminal " when printing to Immediate Window

Given the function below, which is to be used in the debug window

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

The Terminal " may be dropped for -1 Byte, leaving the string unclosed and the program shall execute the same, without error

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

Even more surprising than this is that this may be done within fully defined subroutines.

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

The subroutine above runs as expected and autoformats to

Sub a()
h = "Hello": Debug.Print h; ", World!"
End Sub
Taylor Scott
la source
1

Use Truthy and Falsey Variables in conditionals

Sometimes called implicit type conversion - directly using a number type in a If,[IF(...)] or IIf(...) statement, by using the truthy and falsey nature of that number can absolutely save you some bytes.

In VBA, any number type variable that is non-zero is considered to be truthy ( and thus zero, 0, is the only value falsey) and thus

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

may be condensed to

If B Then C=B Else C=D

and further to

C=IIf(B,B,D)
Taylor Scott
la source
1

Address Sheets By Name

Instead of Addressing a WorkSheet object by calling

Application.ActiveSheet
''  Or 
ActiveSheet   

One may use

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

Or More preferably one may access the object directly and use

Sheet1
Taylor Scott
la source
1

Exponentiation and LongLongs in 64-Bit VBA

The general form of exponentiation,

A to the power of B

Can be represented as in VBA as

A^B 

But Only in 32-Bit Installs of Office, in 64-Bits installs of Office, the shortest way that you may represent without error this is

A ^B

This is because in 64-Bit versions of VBA ^ serves as both the exponentiation literal and the LongLong type declaration character. This means that some rather odd-looking but valid syntax can arise such as

a^=2^^63^-1^

which assigns variable a to hold the max value of a Longlong

Taylor Scott
la source
1

Compress Byte Arrays as String

For challanges that require the solution to hold constant data, it shall may be useful to compress that data as a single string and to then iterate across the string to fetch the data.

In VBA, any byte value may be directly converted to a character with

Chr(byteVal)

And a long or integer value may be converted to two characters with

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

So for a byte array a compression algorithm would look something like

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$

Noting that the Select Case section is implemented due to the characters which may not be stored as literals in the string.

From the resulting string, which will look something like

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

The data may then be extracted using the Asc and Mid functions, eg

i=Asc(Mid(t,n+1))
Taylor Scott
la source
1

Use Improper Constants

VBA allows, in some cases, for the use of unlisted or improper constants in expressions which require constant values. These are often legacy values, and shorter in length than the proper values.

For example the values below may be used when letting a value be held by the rng.HorizantalAlignment property.

ImproperProperGeneral ConstantxlHAlign  Constant11xlGeneralxlHAlignGeneral24131xlLeftxlHAlignLeft34108xlCenterxlHAlignCenter44152xlRightxlHAlignRight55xlFillxlHAlignFill64130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection84117xlDistributedxlHAlignDistributed

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

rng.HorizantalAlignment=-4108

may be shortened down to

rng.HorizantalAlignment=3

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

Taylor Scott
la source
1

In Excel, Create Numeric Arrays by Coercing Ranges

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

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

Example

For instance,

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

may be written as

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

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

For Each s In[{1,3,5,7,9,2,4,6,8}]
Taylor Scott
la source