Dicas para jogar golfe no VBA

16

Semelhante a isso , isso e essa pergunta ...

Que dicas gerais você tem para jogar golfe VBA? Estou procurando idéias que possam ser aplicadas aos problemas de código de golfe em geral que sejam pelo menos um pouco específicos VBA(por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

Embora tenha trabalhado com outros idiomas, sou mais forte VBAe não vejo muitos jogadores usando VBAeste site.

Gaffi
fonte
Convertido em Wiki da comunidade de acordo com a política.
dmckee
Desculpe, não foi automático da minha parte!
Gaffi
Sem problemas. Na verdade, eles tomaram o poder de tirar as perguntas da CW dos usuários (acho que você ainda pode dar respostas). Você pode sinalizar para atenção do moderador, mas a pouca atividade que o CodeGolf obtém dificilmente é necessária.
dmckee
2
O VBA é uma linguagem relativamente detalhada com poucos atalhos de sintaxe. Se você está buscando a melhor pontuação, o VBA pode não ser uma boa escolha. Se você está procurando aprimorar suas habilidades, mais poder para você.
Mr. Llama
2
@GigaWatt Aprimorando minhas habilidades. Na verdade, desde que brinquei com desafios diferentes, já aprendi alguns truques novos para trabalhar com o VBA! Não espero vencer desafios reais de código-golfe com o VBA, mas é uma boa prática. :-)
Gaffi 20/03/2012

Respostas:

8

Explorar o ByRefpadrão ao chamar subs

Às vezes, é possível usar uma Subchamada no lugar de a Functionpara salvar alguns caracteres adicionais ...

Isso ( 87 caracteres)

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

pode ser retrabalhado para ( 73 caracteres):

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

Observe que isso NÃO funcionará para sempre, embora pareça que você nunca está reatribuindo bo valor.

O item acima não usa uma Functionchamada, mas explora a funcionalidade ByRef("Por referência") da Subchamada. O que isso significa é que o argumento passado é a mesma variável que na função de chamada (em oposição a uma ByValpassagem "Por valor", que é uma cópia). Quaisquer modificações na variável passada serão convertidas de volta para a função de chamada.

Por padrão, o aceita todos os argumentos como ByRef, portanto, não há necessidade de usar caracteres para definir isso.

O exemplo acima pode não se traduzir perfeitamente para você, dependendo do valor de retorno da sua função. (ou seja, retornar um tipo de dados diferente do que é passado), mas isso também permite a possibilidade de obter um valor de retorno enquanto modifica sua variável original.

Por exemplo:

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
fonte
7

Escreva e execute o código VBA na janela imediata

A janela imediata avalia qualquer declaração executável do VBA válida. Simplesmente insira uma instrução na Janela Imediata como faria no editor de código. Ele executa rapidamente o código VBA e pode salvar muitos caracteres adicionais porque:

  1. Colocar o ponto de interrogação (?) No início da instrução informa à Janela Imediata para exibir o resultado do seu código.

insira a descrição da imagem aqui

  1. Você não precisa usar um Sub e End Sub no seu código.

insira a descrição da imagem aqui


Aqui está o exemplo do código VBA na janela Immediate para responder à postagem do PPCG com a tag : A letra A sem A

?Chr(88-23);

respondido por Joffan .


Imagens de crédito: Excel Campus

Anastasiya-Romanova 秀
fonte
11
Que usa um ambiente REPL embora? Isso significa que é apenas um trecho, e não um programa ou função
Caird coinheringaahing
Eu acho que outro exemplo a ser adicionado é que você também pode criar variáveis ​​em linha; por exemplo, a="value":?aprimeiro define o valor de ae depois o imprime.
Greedo
6

Verificações condicionais antes do loop

Algumas verificações condicionais são redundantes quando usadas em conjunto com loops. Por exemplo, um Forloop não será processado se a condição inicial estiver fora do escopo da condição em execução.

Em outras palavras, isso ( 49 caracteres):

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

Pode ser transformado neste ( 24 caracteres):

For C = A To A + B ' if B is 0 or less, then the code continues past Next, unabated.
'...
Next
Gaffi
fonte
O comentário na parte inferior está incorreto. Se B = 0, o loop será inserido. pastebin.com/97MBB7hq
QHarr 13/08
5

Declaração Variável

Na maioria dos casos, no VBA, você pode deixar de fora Option Explicit(geralmente omitido por padrão) e pular Dimmuitas de suas variáveis.

Ao fazer isso, este ( 96 caracteres ):

Option Explicit

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

Torna-se este ( 46 caracteres):

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

Se você precisar usar determinados objetos (por exemplo, matrizes), ainda poderá precisar Dimdessa variável.

Gaffi
fonte
Espere um segundo, você aceitou sua própria resposta à sua pergunta. Não é legal, cara.
Taylor Scott
11
@TaylorScott É uma publicação na wiki - não há pontos, e neste caso, não há uma única melhor resposta. :) Aceito a resposta ~ 5 anos atrás para evitar uma bandeira na minha lista de perguntas.
Gaffi 28/05
11
@TaylorScott também se você aceitar a sua própria resposta, você não obter 15 ou 2 (para aceitar)
Caird coinheringaahing
5

Evaluate() E []

Como foi apontado anteriormente, as chamadas de faixa codificadas podem ser reduzidas usando a [A1]notação entre colchetes . No entanto, tem muitos outros usos além disso.

De acordo com a documentação do MSDN , o Application.Evaluate()método usa um único argumento Name, conforme definido pela convenção de nomenclatura do Microsoft Excel.

NB [string]é uma abreviação de Evaluate("string")(observe as ""marcas de fala que indicam o tipo de dados da string), embora haja algumas diferenças importantes abordadas no final.

Então, o que tudo isso significa em termos de uso?

Essencialmente, [some cell formula here]representa uma célula em uma planilha do Excel, e você pode colocar praticamente qualquer coisa nela e obter tudo o que poderia com uma célula normal

O que se passa

Em resumo, com exemplos

  • Referências no estilo A1. Todas as referências são consideradas referências absolutas.
    • [B7] retorna uma referência a essa célula
    • Como as referências são absolutas, ?[B7].Addressretornos"B$7$"
  • Intervalos Você pode usar os operadores de intervalo, interseção e união (dois pontos, espaço e vírgula, respectivamente) com referências.
    • [A1:B5]retorna uma referência de intervalo para A1:B5(Intervalo)
    • [A1:B5 A3:D7]retorna uma referência de intervalo para A3:B5(Intersect)
    • [A1:B5,C1:D5]retorna uma referência de intervalo para A1:D5(tecnicamente A1:B5,C1:D5) (União)
  • Nomes definidos
    • Usuário definido como [myRange]referindo-se a A1: G5
    • Automático, como nomes de tabelas [Table1](possivelmente menos úteis para codegolf)
    • Qualquer outra coisa que você possa encontrar no menu [Formulas]>[Name Manager]
  • Fórmulas
    • Muito útil ; qualquer fórmula que possa entrar em uma célula pode entrar Evaluate()ou[]
    • [SUM(1,A1:B5,myRange)]retorna a soma aritmética dos valores nos intervalos que myRange aqui se refere a um nome de pasta de trabalho e não a uma variável VBA
    • [IF(A1=1,"true","false")](1 byte menor que o equivalente em vba Iif([A1]=1,"true","false"))
    • Fórmulas de matriz [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]- une todas as cadeias no intervalo cujo comprimento é maior que 2 com um espaço
  • Referências externas
    • Você pode usar o !operador para se referir a uma célula ou a um nome definido em outra pasta de trabalho
    • [[BOOK1]Sheet1!A1]retorna uma referência de intervalo para A1 no BOOK1 ou ['[MY WORKBOOK.XLSM]Sheet1!'A1]para o mesmo emMY WORKBOOK
    • Observe as 'pastas de trabalho com espaços em seus nomes e a falta de extensão das pastas de trabalho nomeadas padrão ( BOOK+n)
  • Objetos de gráfico (consulte o artigo MSDN)

NB: eu fiz uma pergunta no SO para essas informações, então dê uma olhada para uma melhor explicação

O que sai

Semelhante ao que entra, o que sai inclui tudo o que uma célula da planilha pode retornar. Estes são os tipos de dados padrão do Excel (e seus equivalentes em VBA):

  • Lógico ( Boolean)
  • Texto ( String)
  • Numérico ( Double)
  • Error ( Variant/Error) (são erros sem interrupção, ou seja, não interrompem a execução do código, ?[1/0]executam bem)

Mas há algumas coisas que podem ser retornadas que as células não podem:

  • Referência de faixa ( Range) (consulte as seções acima)
  • Matrizes ( Variant())

Matrizes

Como foi mostrado, []pode ser usado para avaliar fórmulas de matriz que retornam um dos tipos de dados padrão do Excel; por exemplo, [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]qual retorna Text. No entanto, Evaluatetambém pode retornar matrizes do Varianttipo. Estes podem ser

Codificado:

[{1,2;3,4}]- gera uma matriz 2D: ,é o separador de colunas, ;separa linhas. Pode gerar uma matriz 1D

Fórmulas de matriz:

[ROW(A1:A5)]- gera uma matriz 2D{1,2,3,4,5} , ou seja, (2,1) é o segundo item (ainda que algumas funções gerem matrizes 1D)

  • Por qualquer motivo, algumas funções não retornam matrizes por padrão

[LEN(A1:A5)] gera apenas o comprimento do texto na 1ª célula de um intervalo

  • No entanto, estes podem ser coagidos para fornecer matrizes

Split([CONCAT(" "&LEN(A1:A5))]) dá uma matriz 1D de 0 a 5, onde o primeiro item está vazio

[INDEX(LEN(A1:A5),)]é outra solução alternativa, essencialmente você deve empregar uma função de manipulação de matriz para obter o comportamento de retorno de matriz desejado, semelhante a adicionar um significado RAND()para tornar voláteis as fórmulas da planilha.

  • Fiz uma pergunta no SO para tentar obter informações melhores sobre isso , edite / comente com melhores opções se você as encontrar

Evaluate() vs []

Existem algumas diferenças entre Evaluate()e []estar ciente de

  1. Strings vs codificados
    • Talvez a diferença mais importante, Evaluate utilize uma entrada de string onde [] exigiu uma entrada codificada
    • Isso significa que seu código pode construir a corda com variáveis eg Evaluate("SUM(B1,1,"&v &",2)")resumiria [B1], 1, 2e variávelv
  2. Matrizes

    Ao retornar uma matriz, apenas o botão Avaliar pode ser usado com um índice de matriz, portanto

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

    é equivalente a

    i=[ROW(A1:A5)]:v=i(1,1) ''#23 bytes
Greedo
fonte
Desculpe pelo post gigantesco, se alguém achar que pode tornar as áreas mais concisas / se você tiver dicas a acrescentar, fique à vontade. Além disso, embora eu tenha pesquisado um pouco disso, uma boa parte foi encontrada através da experimentação no VBA; portanto, se você detectar erros de percepção, algo está faltando, não hesite em comentar / editar de acordo!
Greedo
11
Na verdade, a última seção sobre matrizes é um pouco fora - ele pode ser usado na janela imediatai=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott
@TaylorScott Então você pode, eu não sabia que era possível definir / manter valores em variáveis ​​que ainda não estavam definidas, mas suponho que seja porque ainda estou começando a entender as 1 linhas da janela Immediate. Atualizei de acordo.
Greedo
Isso funciona com o Match? Eu tentei, mas sempre retorna erros. Eu estava passando uma matriz em vez de um intervalo, no entanto.
seadoggie01
5

Combinar Nextdeclarações

Next:Next:Next

Pode ser condensado até

Next k,j,i

onde os iterators para as Forlaçadas são i, j, ek - nessa ordem.

Por exemplo, o abaixo (69 bytes)

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

Pode ser condensado em até 65 bytes

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

E, na medida em que isso afeta a formatação e o recuo, acho que a melhor abordagem para lidar com isso é alinhar a próxima declaração pela mais externa. Por exemplo.

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

Reduzindo If declarações

Ao atribuir uma variável usando uma If ... Then ... Elseverificação condicional , você pode reduzir a quantidade de código usada, eliminando oEnd If colocando toda a verificação em uma linha.

Por exemplo, este ( 37 caracteres):

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

Pode ser reduzido a isso ( 30 caracteres)

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

Se você tiver mais de uma condicional aninhada, também poderá minimizá-las desta maneira:

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

Observe que :permite adicionar mais de uma linha / comando dentro de umIf bloco.

Em casos simples como esse, você também pode remover a Elseconfiguração da variável antes da Ifverificação ( 25 caracteres):

c = a
If a < b Then c = b

Ainda melhor, o acima pode ser reduzido ainda mais usando a IIf()função ( 20 caracteres):

c = IIf(a < b, b, a)
Gaffi
fonte
3

Reduzir Range("A1")e curtir chamadas

Range("A1").Value(17 bytes) e o mais simples Range("A1")(11 bytes) pode ser reduzido para [A1](4 bytes)

Taylor Scott
fonte
2
Ou, em geral, o uso de []para substituir Evaluate()no VBA é muito mais versátil do que apenas chamadas de intervalo. Por exemplo, você pode usá-lo para substituir WorksheetFunction.FuncName(args)com apenas [FuncName(args)], como ?[SUMPRODUCT({1,3,5},{2,7,-1})]ou o muito útil [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo
Greedo, essa é uma funcionalidade incrivelmente importante que eu não sabia que você deveria adicionar como sua própria resposta.
Taylor Scott
11
Claro, vou escrever algo em breve. Sim Evaluate("str")ou taquigrafia [str]é muito poderoso no VBA, descobri recentemente e acho que também será útil para o golfe!
Greedo
Muito útil, enoughso que estou indo para trás com as minhas respostas para ver se eu posso largar a minha bytecount em qualquer causa disso
Taylor Scott
3

Remover espaços

O VBA será formatado automaticamente para adicionar muito espaçamento que ele realmente não precisa. Há uma resposta na meta que faz muito sentido para mim porque podemos descontar os bytes adicionados pela formatação automática. É importante sempre verificar se você não removeu muito, no entanto. Por exemplo, aqui está uma resposta minha que foi reduzida em quase 22% apenas com a remoção de espaços:

Versão original: (188 bytes)

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

Versão reduzida: (146 bytes)

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 você copiar / colar a versão reduzida no VBA, ela será automaticamente expandida para o original. Você pode brincar com onde é válido remover espaços. Os que encontrei até agora parecem seguir o padrão em que o VBA espera que um determinado comando apareça porque, sem ele, não é um código válido. Aqui estão alguns que eu encontrei até agora:

  • Antes e depois de qualquer operação matemática: +-=/*^etc.
  • Antes Toe Stepem uma Fordeclaração:For x=-3To 3Step 0.05
  • Na verdade, antes de qualquer palavra reservada ( To, &, Then, etc.) se for precedido por um literal, como um número, ), ?, %, etc.
  • Após a &combinação de strings:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • Após chamadas de função: If s=StrReverse(s)Then
  • Nas chamadas de função: Replace(Space(28)," ",0)
Engenheiro Toast
fonte
Qual é a regra sobre caracteres não espaciais adicionados por meio da formatação automática. Algo como? vs Printeu vejo é aceitável, mas colocar declaração de tipo como &imediatamente após uma variável, por exemplo, Debug.?a&"z"Debug.Print a&; "z". O ;caractere adicionado é essencial para a execução do código - isso ainda é permitido?
Greedo
2
@ Gregedo Eu vejo da maneira que a meta resposta descreveu: Se você pode copiar / colar no editor e o código será executado, tudo bem. IE, se o VBA adiciona automaticamente o caractere novamente quando você cola o código, tudo bem.
Engineer Toast
11
@EngineerToast, você pode realmente remover mais um byte do seu exemplo: If i=1 Then pode tornar-se If i=1Then , pois, como regra geral uma palavra reservada que segue um literal, seja um número, ), ?, %, .. etc, não precisam ser separados por um espaço
Taylor Scott
11
@EngineerToast, você também pode soltar um byte de seu ponto de bala terceiro como você pode soltar os espaços entre uma )(ou qualquer outro não-número literal) e&
Taylor Scott
3

Prepare-se para Pixel Art

A arte em pixel é de longe uma das áreas mais fortes do Excel, pois não há necessidade de construir uma tela, pois ela já existe para você - tudo o que você precisa fazer é fazer alguns pequenos ajustes

1) Faça as células quadradas

Cells.RowHeight=48

ou, alternativamente, por mais 1 byte, mas é muito mais fácil trabalhar com

Cells.ColumnWidth=2

2) Colorir a faixa necessária

Qualquer Rangeobjeto pode ser colorido chamando

`MyRangeObj`.Interior.Color=`ColorValue`

Nota: isso pode e deve ser combinado com outros truques mencionados neste wiki, como referenciar intervalos pelo uso da []notação (por exemplo [A1:R5,D6]) sobre o uso de um Cells(r,c)ou umRange(cellAddress) chamada. Além disso, conforme observado neste wiki, isso pode ser combinado com um valor de cor negativo para reduzir o tamanho das referências de cores

Referências Rápidas

Referência de Gama

Célula A1 pode ser referenciada de qualquer uma das seguintes maneiras

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

e a gama A1:D4 podem ser referenciados de qualquer uma das seguintes maneiras

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

Referência de cores

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

Simplifique as funções incorporadas

Ao usar determinadas funções com freqüência, reatribua-as a uma função definida pelo usuário.

O código a seguir ( 127 caracteres) pode ser reduzido 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

para ( 124 caracteres):

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 isso com o truque ByRef , você pode salvar ainda mais caracteres (até 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

Faça isso criteriosamente, pois o VBA ocupa muitos caracteres para definir a Function. O segundo bloco de código seria realmente maior que o primeiro com um número menor de Format()chamadas.

Gaffi
fonte
2
na última, você não precisa a chamada atribuição, o que significa que a = f(w)pode ser reduzido af w
Taylor Scott
3

STDIN e STDOUT

Introdução a Subrotinas Functiones através de variáveis ​​de entrada

Public Sub A(ByRef B as String)

Pode ser reduzido para

Sub a(b$) 

O PubliceByRef chamadas são o padrão para o VBA e, portanto, implícitas, e podem (quase) sempre ser descartadas.

O tipo literal $força ba ser do tipoString .

Outros literais de tipo

  • ! solteiro
  • @ Moeda
  • # Duplo
  • % Inteiro
  • $ Corda
  • & Grandes
  • ^ LongLong (somente 64 bits)

Além disso, é geralmente aceito que você possa deixar a variável de entrada como o tipo padrão Variante deixar os erros baseados em tipo sem tratamento. Por exemplo. Sub E(F)no qual Fse espera que seja do tipo Boolean[](que seria passado para a rotina comoE Array(True, False, False) )

Introdução a Subrotinas e funções imediatas da janela viaCells

O VBA não tem um console totalmente funcional e, portanto, não tem qualquer oficial STDIN, e, portanto, permite a alguns jogadas com entradas passantes.

No Excel, geralmente é aceito receber informações de uma célula ou intervalo de células, o que pode ser feito como

s=[A1]

que coloca implicitamente o .valueda célula [A1](que também pode ser referenciado comocells(1,1) ourange("A1")

Exemplo de problema: Exibir a entrada em uma caixa de mensagens

Via Sub-rotina Sub A:msgbox[A1]:End Sub

Via janela Função msgbox[A1]

Introdução através de argumentos de compilação condicional

Os Projetos VBA suportam a tomada de argumentos na linha de comando ou nas Propriedades do VBAProject (veja através do explorador de projeto -> [Seu projeto VBA] - (Clique com o botão direito do mouse) -> Propriedades do VBAProject -> Argumentos de compilação condicionais)

Isso é amplamente útil para desafios de código de erro

Dado o argumento de compilação condicional n=[some_value], isso permite executar o código que produzirá um código de erro, com base no valor de n. note que isso exige uma adição de 2 bytes ao seu código para a n=seção de argumentos de compilação condicional do Painel de Propriedades do VBAProject.

Código de exemplo

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

Saída através do valor da função

Não há muito a dizer aqui, a forma geral de citar abaixo é tão compacta quanto possível.

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

OBSERVAÇÃO: na grande maioria dos casos, é mais byte converter o método em uma sub-rotina e enviar para a janela do VBE imediatamente (veja abaixo)

Saída de Subrotinas Functiones através da janela do VBE Immediates

A saída para a janela imediata do VBE (também conhecida como janela de depuração do VBE) é um método de saída comum para o VBA para desafios baseados em texto; no entanto, é importante lembrar que a Debug.Print "Text"chamada pode ser substancialmente prejudicada.

Debug.Print "Text"

é funcionalmente idêntico ao

Debug.?"Text"

como ?formatação automática para Print.

Saída de Subrotinas e funções da janela VBE Immediates através de outros métodos

Em raras ocasiões, quando a situação é certa, você pode receber informações de algumas das entradas mais triviais disponíveis para o VBA, como o ajustador de tamanho da fonte, o seletor de fontes e o zoom. (Por exemplo, emulando o seletor de tamanho de fonte do Word )

Taylor Scott
fonte
2

Nota rápida sobre formatação

Como o StackExchange usa Markdown e Prettify.js , é possível adicionar um sinalizador de idioma às suas respostas de codificação, o que geralmente as faz parecer mais profissionais. Embora eu não possa garantir que isso o melhore no golfe no VBA, posso garantir que isso fará com que você pareça.

A adição de um dos sinalizadores abaixo transformará

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

para

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

Tags de idioma do VBA

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

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

Nota: o último transforma todos os segmentos de código em sua resposta, enquanto o anterior transforma apenas os seguintes segmentos de código imediatamente

Taylor Scott
fonte
lang-vbEh? - Estranho que isso formate melhor do que lang-vbapara respostas vba.
Greedo
11
@Greedo, isso porque enquanto lang-vbafornecerá destaque, na verdade é apenas o destaque padrão. Aparentemente VBA realmente não foi implementado em Prettify.js, por isso vamos ter que ficar com o destaque VB
Taylor Scott
2

Múltiplo If .. Then verificações

Como em outros idiomas, várias Ifverificações geralmente podem ser combinadas em uma única linha, permitindo o uso de And/ Or(ou seja, &&/ ||em C e outros), que no VBA substitui a Thene a End If.

Por exemplo, com uma condicional aninhada ( 93 caracteres):

'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

pode se tornar ( 69 caracteres):

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

Isso também funciona com condicionais não aninhados.

Considere ( 84 caracteres):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Isso pode se tornar ( 51 caracteres):

If a = b Or c = b Then            
    d = 0
End If
Gaffi
fonte
11
Nas instruções If - then, a parte "Final - se" é opcional, desde que você escreva o código na linha única.
Stupid_Intern 16/04
@newguy Correto. Veja também esta outra resposta: codegolf.stackexchange.com/a/5788/3862
Gaffi
A declaração acima pode ser mais resumida emd=iif(a=b or c=b,0,d)
Taylor Scott
2

Final For Loops

Ao usar Forloops, umNext linha não precisa de um nome de variável (embora provavelmente seja melhor usar na codificação normal).

Portanto,

For Variable = 1 to 100
    'Do stuff
Next Variable

pode ser reduzido para:

For Variable = 1 to 100
    'Do stuff
Next

(A economia depende do nome da sua variável, embora se você estiver jogando golfe, provavelmente seja apenas 1 caractere + 1 espaço.)

Gaffi
fonte
11
2 caracteres, não se esqueça de contar o espaço!
11684
Eu quase nunca identifico a variável, mesmo no código normal!
DNEP
2

Dividir uma sequência em uma matriz de caracteres

Às vezes, pode ser útil dividir uma sequência em caracteres individuais, mas pode ser necessário um pouco de código para fazer isso manualmente no 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

Em vez disso, você pode usar uma única linha, uma cadeia de funções relativamente mínima para realizar o trabalho:

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

Isso atribuirá sua string sà Variantmatriz a. Porém, tenha cuidado, pois o último item da matriz será uma string vazia ( ""), que precisará ser manuseada adequadamente.

Eis como funciona: A StrConvfunção converte a Stringem outro formato que você especificar. Nesse caso, 64 =vbUnicode , então ele converte para um formato unicode. Ao lidar com cadeias ASCII simples, o resultado é um caractere nulo (não uma cadeia vazia "") , inserido após cada caractere.

A seguir Split, converteremos o resultado resultanteString em uma matriz, usando o caractere nuloChr(0) como delimitador.

É importante observar que Chr(0)não é o mesmo que a string vazia "", e usar Spliton ""não retornará a matriz que você poderia esperar. O mesmo se aplica a vbNullString(mas se você está jogando golfe, por que você usaria uma constante tão detalhada em primeiro lugar?).

Gaffi
fonte
Você deve mencionar que a matriz resultante possui uma sequência vazia adicional no final.
Howard
@ Howard Sim, eu deveria. Estava na minha cabeça enquanto eu estava digitando isso, deve ter escapado da minha mente.
Gaffi
2

Usando With (Às vezes! Ver nota de rodapé)

Usando o With instrução pode reduzir significativamente o tamanho do código se você usar alguns objetos repetidamente.

isto é ( 80 caracteres):

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

pode ser codificado como ( 79 caracteres):

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

O exposto acima nem é o melhor cenário. Se você usar algo com Application, como Excel.Applicationno Access, a melhoria será muito mais significativa.


* Dependendo da situação, Withpode ou não ser mais eficiente do que isso ( 64 caracteres):

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

Loops infinitos

Considere a substituição

Do While a<b
'...
Loop

ou

Do Until a=b
'...
Loop

com a contagem de bytes antiga, mas mais baixa

While a<b
'...
Wend

Se você precisar sair de um Subou Functionprematuramente, em vez deExit ...

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

considerar End

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

Observe que Endinterrompe toda a execução do código e limpa quaisquer variáveis ​​globais, portanto, use com sabedoria

Greedo
fonte
Você deve considerar reescrever a última seção ( Fore End) para refletir que o caso 100nunca serão atingidos e adiciona um byte desnecessário
Taylor Scott
Além disso, enquanto isso é muito legível, você pode considerar a remoção do espaço em branco para mostrar os possíveis benefícios desses métodos melhores (é sempre bom abusar do autoformatting em VBA para codegolfing)
Taylor Scott
2

Use Spc(n)sobre Space(n),[Rept(" ",n)] ouString(n," ")

Ao tentar inserir vários espaços de comprimento n, use

Spc(n)              ''  6  bytes

sobre

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

Nota: Não sei por que, mas parece que você não pode atribuir a saída de Spc(n)a uma variável e que ela deve ser impressa diretamente - portanto, em certos casos, Space(n)ainda é o melhor caminho a percorrer.

Taylor Scott
fonte
2

Reduzir Debug.Printe Printligar

Debug.Print [some value] 

(12 bytes; observe o espaço à direita) pode ser reduzido para

Debug.?[some value]

(7 bytes; observe a falta de espaço à direita).

Similarmente,

Print 

(6 bytes) pode ser reduzido para

?

(1 byte).

Além disso, ao operar no contexto de uma função de janela imediata anônima do VBE, a Debuginstrução pode ser descartada inteiramente e, em vez disso, a impressão na janela imediata do VBE via ?pode ser assumida como STDIN / STDOUT

Caracteres especiais

Ao imprimir strings, você também pode usar caracteres especiais no lugar de &. Eles permitem formatos alternativos no que é impresso ou na remoção de espaços em branco

Para juntar cadeias variáveis, em vez de

Debug.Print s1 &s2

Você pode usar um ponto e vírgula ;

Debug.?s1;s2

Esse ponto-e-vírgula é o comportamento padrão para seqüências consecutivas, desde que não haja ambiguidade. Portanto, elas são válidas:

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

Mas não

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

Observe que a; no final de uma linha suprime uma nova linha, pois as novas são adicionadas por padrão após cada impressão. Contagem de bytes retornados pelo código VBA está em debate

Para ingressar em uma guia, use uma vírgula ,(na verdade, 14 espaços, mas de acordo com)

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

Por fim, você pode usar declarações de tipo para unir seqüências de caracteres em vez de; cada uma tendo seu próprio efeito leve na formatação. Para todos os itens abaixo a = 3.14159é a primeira linha

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
fonte
2

Use um ajudante Sub paraPrint

Se o código exigir o uso de mais de seis Debug.? instruções, você poderá reduzir os bytes substituindo todos os Debug. linhas com uma chamada para um Sub como o abaixo. Para imprimir uma linha em branco, é necessário chamar, p ""pois é necessário um parâmetro.

Sub p(m)
Debug.?m
End Sub
Ben
fonte
11
Para imprimir uma nova linha com a qual você precisaria apenas p""ou se não puder ser terminada p",. No entanto, na grande maioria dos casos em que isso se aplica, faz mais sentido usar uma variável de sequência e imprimir apenas a variável de sequência no final.
Taylor Scott
1

Use em Array() Choose()vez de SelectouIf...Then

Ao atribuir uma variável com base no valor de outra variável, faz sentido escrever as etapas com If...Thenverificações, da seguinte maneira:

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

No entanto, isso pode ocupar muito espaço de código se houver mais de uma ou duas variáveis ​​para verificar (geralmente ainda existem maneiras melhores de fazer isso).

Em vez disso, a Select Caseinstrução ajuda a reduzir o tamanho das verificações, envolvendo tudo em um bloco, da seguinte maneira:

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

Isso pode levar a um código muito menor, mas em casos muito simples como esse, existe um método ainda mais eficiente: Choose()Essa função seleciona um valor de uma lista, com base no valor passado para ela.

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

A opção para selecionar ( aneste caso) é um valor inteiro passado como o primeiro argumento. Todos os argumentos subseqüentes são os valores para escolher (indexado em 1, como a maioria dos VBA). Os valores podem ser de qualquer tipo de dados, desde que correspondam à variável que está sendo definida (ou seja, os objetos não funcionam sem a Setpalavra - chave) e podem até ser expressões ou funções.

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

Uma opção adicional é usar a Arrayfunção para obter o mesmo efeito e salvar outro caractere:

b = Array(5 + 4, String(7,"?"))(a)
Gaffi
fonte
Um uso interessante e possivelmente muito benéfico para o golfe é usar isso em conjunto com uma IIf()ou outra 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

Valores RGB com deslocamento de bits

Devido à maneira como o Excel lida com cores (número inteiro hexadecimal de 6 caracteres não assinado), você pode usar números inteiros assinados negativamente, dos quais o Excel usará apenas os 6 bytes corretos para atribuir um valor de cor

Isso é um pouco confuso, então alguns exemplos são fornecidos abaixo

Digamos que você queira usar a cor branca, que é armazenada como

rgbWhite

e é equivalente a

&HFFFFFF ''#value: 16777215

Para reduzir isso tudo o que precisamos fazer é encontrar um valor hexadecimal negativo que termine em FFFFFFe, como valores hexadecimais negativos devem estar no formato de FFFFXXXXXX(como Xum hexadecimal válido), contando de FFFFFFFFFF( -1) a FFFF000001(-16777215 )

Sabendo disso, podemos generalizar que a fórmula

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

Usando isso, algumas conversões úteis são

rgbWhite = &HFFFFFF = -1 
rgbAqua  = &HFFFF00 = -256
16747627 = &HFF8C6B = -29589
Taylor Scott
fonte
É bom saber o que estava acontecendo lá, eu acabei de descobrir isso acidentalmente nessa pergunta - mas essa explicação clara mostra exatamente como funciona. Outra coisa a ter em mente é que certas cores principais podem ser reduzidas com operadores matemáticos; rgbWhite= 2^24-1Embora poderia ser reduzida ainda mais se você perder fora da -1 para obter cerca de lá
Greedo
11
Na verdade, aqui está uma lista de cores com suas representações matemáticas, que são mais curtos do que tanto as versões positivas ou negativas decimais: &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 não necessariamente completos, mas eu acho que fiz um trabalho bastante minucioso
Greedo
1

Omita o terminal "ao imprimir na janela imediata

Dada a função abaixo, que deve ser usada na janela de depuração

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

O Terminal "pode ser descartado por -1 Byte, deixando a string não fechada e o programa deve executar o mesmo, sem erros

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

Ainda mais surpreendente do que isso é que isso pode ser feito dentro de sub-rotinas totalmente definidas.

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

A sub-rotina acima é executada conforme o esperado e formata automaticamente

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

Use Variáveis ​​Truthy e Falsey em condicionais

Às vezes chamada de conversão de tipo implícito - directamente utilizando um tipo de número em um If, [IF(...)]ouIIf(...) declaração, usando a natureza truthy e Falsey desse número pode absolutamente poupar alguns bytes.

No VBA, qualquer variável de tipo numérico diferente de zero é considerada verdadeira (e, portanto, zero 0, é o único valor falsey) e, portanto,

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

pode ser condensado para

If B Then C=B Else C=D

e ainda mais

C=IIf(B,B,D)
Taylor Scott
fonte
1

Folhas de endereço por nome

Em vez de endereçar um WorkSheetobjeto chamando

Application.ActiveSheet
''  Or 
ActiveSheet   

Pode-se usar

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

Ou, mais preferencialmente, pode-se acessar o objeto diretamente e usar

Sheet1
Taylor Scott
fonte
1

Exponenciação e LongLong es no VBA de 64 bits

A forma geral de exponenciação,

A to the power of B

Pode ser representado como no VBA como

A^B 

Mas somente em instalações de 32 bits do Office , em instalações de 64 bits do Office, a maneira mais curta que você pode representar sem erro é

A ^B

Isso ocorre porque nas versões de 64 bits do VBA ^serve tanto o literal de exponenciação quanto o LongLongcaractere de declaração de tipo . Isso significa que pode surgir uma sintaxe bastante estranha, mas válida, como

a^=2^^63^-1^

que atribui a variável apara armazenar o valor máximo de umLonglong

Taylor Scott
fonte
1

Compactar matrizes de bytes como sequência

Para desafios que exigem que a solução mantenha dados constantes, pode ser útil compactar esses dados como uma única sequência e, em seguida, percorrer a sequência para buscar os dados.

No VBA, qualquer valor de byte pode ser convertido diretamente em um caractere com

Chr(byteVal)

E um valor longou integerpode ser convertido em dois caracteres com

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

Portanto, para uma bytematriz, um algoritmo de compressão seria algo como

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$

Observando que a Select Caseseção é implementada devido aos caracteres que não podem ser armazenados como literais na string.

A partir da string resultante, que será algo como

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

Os dados podem então ser extraídos usando as funções Asce Mid, por exemplo

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

Use constantes impróprias

O VBA permite, em alguns casos, o uso de constantes não listadas ou impróprias em expressões que exigem valores constantes. Geralmente, esses são valores herdados e mais curtos que os valores adequados.

Por exemplo, os valores abaixo podem ser usados ​​ao permitir que um valor seja mantido pela rng.HorizantalAlignmentpropriedade.

ImpróprioAdequadoConstante GeralxlHAlign  Constante1 11 1xlGeneralxlHAlignGeneral2-4131xlLeftxlHAlignLeft3-4108xlCenterxlHAlignCenter4-4152xlRightxlHAlignRight55xlFillxlHAlignFill6-4130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection8-4117xlDistributedxlHAlignDistributed

Isso significa, por exemplo, que definir uma célula para ter seu texto centralizado com

rng.HorizantalAlignment=-4108

pode ser reduzido para

rng.HorizantalAlignment=3

substituindo o valor constante incorreto 3pelo valor adequado -4108. Observe que, se você buscar o rng.HorizantalAlignmentvalor da propriedade, ele retornará o valor adequado. Nesse caso, isso seria -4108.

Taylor Scott
fonte
1

No Excel, crie matrizes numéricas por faixas de coagulação

Quando um conjunto unidimensional constante de números de comprimento misto, Sfor necessário, deve ser mais eficiente usar a [{...}]notação para declarar um intervalo e depois coagi-lo em uma matriz numérica, em vez de usar a Split(String)notação ou similar.

Usando esse método, uma mudança de Δcontagem de bytes=-5 bytes deve ser acumulado para todos S.

Exemplo

Por exemplo,

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

pode ser escrito como

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

Também é importante notar que, embora esse método não permita a indexação direta, ele permite a iteração diretamente no loop for, ou seja,

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