Consejos para jugar golf en VBA

16

Similar a esto , esto y esta pregunta ...

¿Qué consejos generales tienes para jugar al golf VBA? Estoy buscando ideas que se puedan aplicar a los problemas de golf de código en general que sean al menos algo específicos VBA(por ejemplo, "eliminar comentarios" no es una respuesta). Por favor, publique un consejo por respuesta.

Si bien he trabajado con otros idiomas, soy más fuerte VBAy no veo que muchos golfistas utilicen VBAeste sitio.

Gaffi
fuente
Convertido a Wiki de la comunidad según la política.
dmckee
Lo siento, eso no fue automático de mi parte!
Gaffi
Sin problemas. En realidad, se han tomado el poder de hacer preguntas CW lejos de los usuarios (creo que todavía puedes responder). Podrías marcar la atención del moderador, pero tan poca actividad como CodeGolf obtiene eso es apenas necesario.
dmckee
2
VBA es un lenguaje relativamente detallado con pocos atajos de sintaxis. Si buscas el mejor puntaje, VBA puede no ser una buena opción. Si estás buscando perfeccionar tus habilidades, más poder para ti.
Sr. Llama
2
@GigaWatt Afinando mis habilidades es. En realidad, desde que jugué con diferentes desafíos, ¡ya he aprendido algunos trucos nuevos para trabajar con VBA! No espero ganar ningún desafío de código real de golf con VBA, pero es una buena práctica. :-)
Gaffi

Respuestas:

8

Explotar el ByRefvalor predeterminado al llamar a subs

A veces es posible usar una Subllamada en lugar de a Functionpara guardar algunos caracteres adicionales ...

Esto ( 87 caracteres)

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

se puede reelaborar para ( 73 caracteres):

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

Tenga en cuenta que esto NO se repetirá para siempre, aunque parece que nunca está reasignando bel valor.

Lo anterior no utiliza una Functionllamada, sino que explota la funcionalidad ByRef("Por referencia") de la Subllamada. Lo que esto significa es que el argumento pasado es la misma variable que en la función de llamada (en oposición a un paso ByVal"Por valor", que es una copia). Cualquier modificación a la variable pasada se traducirá de nuevo a la función de llamada.

Por defecto, toma todos los argumentos como ByRef, por lo que no es necesario usar caracteres para definir esto.

El ejemplo anterior puede no traducirse perfectamente para usted, dependiendo del valor de retorno de su función. (es decir, devolver un tipo de datos diferente al que se pasa), pero esto también permite la posibilidad de obtener un valor de retorno sin modificar la variable original.

Por ejemplo:

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

Escriba y ejecute el código VBA en la ventana Inmediato

La ventana Inmediato evalúa cualquier instrucción ejecutable VBA válida. Simplemente ingrese una declaración en la ventana Inmediato como lo haría en el editor de código. Ejecuta rápidamente el código VBA y puede guardar muchos caracteres adicionales porque:

  1. Poner el signo de interrogación (?) Al comienzo de la declaración le dice a la Ventana Inmediato que muestre el resultado de su código.

ingrese la descripción de la imagen aquí

  1. No necesita usar un Sub y End Sub en su código.

ingrese la descripción de la imagen aquí


Aquí está el ejemplo del código VBA en la ventana Inmediato para responder la publicación de PPCG con la etiqueta : La letra A sin A

?Chr(88-23);

respondido por Joffan .


Imágenes de crédito: Excel Campus

Anastasiya-Romanova 秀
fuente
1
Sin embargo, ¿eso usa un entorno REPL? Eso significa que es solo un fragmento, no un programa o función
caird coinheringaahing
Creo que otro ejemplo para agregar puede ser que también puede crear variables en línea; por ejemplo, a="value":?aprimero establece el valor de a, luego lo imprime.
Greedo
6

Verificaciones condicionales antes de bucles

Algunas verificaciones condicionales son redundantes cuando se usan junto con bucles. Por ejemplo, un Forbucle no se procesará si la condición de inicio está fuera del alcance de la condición de ejecución.

En otras palabras, esto ( 49 caracteres):

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

Se puede convertir en esto ( 24 caracteres):

For C = A To A + B ' if B is 0 or less, then the code continues past Next, unabated.
'...
Next
Gaffi
fuente
El comentario en la parte inferior es incorrecto. Si B = 0, se ingresará al bucle. pastebin.com/97MBB7hq
QHarr
5

Declaración Variable

En la mayoría de los casos en VBA, puede omitir Option Explicit(a menudo se omite de forma predeterminada, de todos modos) y omitir Dimmuchas de sus variables.

Al hacerlo, esto ( 96 caracteres ):

Option Explicit

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

Se convierte en esto ( 46 caracteres):

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

Si necesita usar ciertos objetos (por ejemplo, matrices), aún puede necesitar Dimesa variable.

Gaffi
fuente
Espere un segundo, aceptó su propia respuesta a su pregunta. No es genial, amigo.
Taylor Scott
1
@TaylorScott Es una publicación de wiki, sin puntos, y en este caso, no hay una sola mejor respuesta. :) Acepto la respuesta ~ hace 5 años para evitar tener una bandera en mi lista de preguntas.
Gaffi
1
@TaylorScott también si acepta su propia respuesta, no obtiene +15 o +2 (por aceptar)
caird coinheringaahing
5

Evaluate() Y []

Como se señaló anteriormente, las llamadas de rango codificadas pueden reducirse utilizando la [A1]notación de corchetes . Sin embargo, tiene muchos más usos además de eso.

De acuerdo con la documentación de MSDN , el Application.Evaluate()método toma un solo argumento, que es un Name, según lo definido por la convención de nomenclatura de Microsoft Excel.

NB [string]es la abreviatura de Evaluate("string")(tenga en cuenta las ""marcas de voz que denotan el tipo de datos de cadena), aunque hay algunas diferencias importantes que se cubren al final.

Entonces, ¿qué significa todo eso en términos de uso?

Esencialmente, [some cell formula here]representa una celda en una hoja de cálculo de Excel, y puede poner casi cualquier cosa en ella y sacar todo lo que pueda con una celda normal

Lo que entra

En resumen, con ejemplos.

  • Referencias de estilo A1. Todas las referencias se consideran referencias absolutas.
    • [B7] devuelve una referencia a esa celda
    • Como las referencias son absolutas, ?[B7].Addressdevuelve"B$7$"
  • Rangos Puede usar los operadores de rango, intersección y unión (dos puntos, espacio y coma, respectivamente) con referencias.
    • [A1:B5]devuelve una referencia de rango a A1:B5(Rango)
    • [A1:B5 A3:D7]devuelve una referencia de rango a A3:B5(Intersect)
    • [A1:B5,C1:D5]devuelve una referencia de rango a A1:D5(técnicamente A1:B5,C1:D5) (Unión)
  • Nombres definidos
    • Usuario definido como [myRange]referirse a A1: G5
    • Automático, como nombres de tablas [Table1](posiblemente menos útil para codegolf)
    • Cualquier otra cosa que pueda encontrar en el menú [Formulas]>[Name Manager]
  • Fórmulas
    • Muy util ; cualquier fórmula que pueda entrar en una celda puede entrar Evaluate()o[]
    • [SUM(1,A1:B5,myRange)]devuelve la suma aritmética de valores en los rangos myRange aquí se refiere al nombre de un libro de trabajo, no a una variable VBA
    • [IF(A1=1,"true","false")](1 byte más corto que el equivalente vba Iif([A1]=1,"true","false"))
    • Fórmulas de matriz [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]: une todas las cadenas en el rango cuya longitud es mayor que 2 con un espacio
  • Referencias externas
    • Puede usar el !operador para referirse a una celda o a un nombre definido en otro libro de trabajo
    • [[BOOK1]Sheet1!A1]devuelve una referencia de rango a A1 en BOOK1 o ['[MY WORKBOOK.XLSM]Sheet1!'A1]para el mismo enMY WORKBOOK
    • Tenga en cuenta los 'libros de trabajo con espacios en sus nombres y la falta de extensión para los libros de trabajo con nombre predeterminados ( BOOK+n)
  • Objetos de gráfico (consulte el artículo de MSDN)

Nota: hice una pregunta sobre SO para obtener esta información, así que eche un vistazo allí para obtener una mejor explicación

Lo que sale

Similar a lo que entra, lo que sale incluye todo lo que una celda de la hoja de trabajo puede devolver. Estos son los tipos de datos estándar de Excel (y sus equivalentes de VBA):

  • Lógico ( Boolean)
  • Texto ( String)
  • Numérico ( Double)
  • Error ( Variant/Error) (estos son errores que no se rompen, es decir, no detienen la ejecución del código, se ?[1/0]ejecuta bien)

Pero hay algunas cosas que pueden devolverse que las celdas no pueden:

  • Referencia de rango ( Range) (ver secciones anteriores)
  • Matrices ( Variant())

Matrices

Como se ha mostrado, []se puede usar para evaluar fórmulas de matriz que devuelven uno de los tipos de datos estándar de Excel; por ejemplo, [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]que vuelve Text. Sin embargo Evaluate, también puede devolver matrices de Varianttipo. Estos pueden ser

Hardcoded:

[{1,2;3,4}]- Emite una matriz 2D: ,es el separador de columna, ;separa las filas. Puede generar una matriz 1D

Fórmulas de matriz:

[ROW(A1:A5)]- genera una matriz 2D{1,2,3,4,5} , es decir (2,1) es el segundo elemento (aunque algunas funciones generan matrices 1D)

  • Por alguna razón, algunas funciones no devuelven matrices por defecto

[LEN(A1:A5)] solo genera la longitud del texto en la primera celda de un rango

  • Sin embargo, estos pueden ser obligados a dar matrices

Split([CONCAT(" "&LEN(A1:A5))]) da una matriz 1D de 0 a 5, donde el primer elemento está vacío

[INDEX(LEN(A1:A5),)]Es otra solución, esencialmente debe emplear una función de manejo de matriz para obtener el comportamiento de retorno de matriz deseado, similar a agregar un sin sentido RAND()para hacer que sus fórmulas de hoja de trabajo sean volátiles.

  • Hice una pregunta sobre SO para tratar de obtener información mejor sobre esto , edite / comente con mejores opciones si las encuentra

Evaluate() vs []

Hay algunas diferencias entre Evaluate()y []tener en cuenta

  1. Cuerdas vs codificadas
    • Quizás la diferencia más importante, Evaluate toma una entrada de cadena donde [] requiere una entrada codificada
    • Esto significa que su código se puede acumular la cadena con variables por ejemplo, Evaluate("SUM(B1,1,"&v &",2)")sería resumir [B1], 1, 2y variablesv
  2. Matrices

    Al devolver una matriz, solo se puede usar Evaluate con un índice de matriz, por lo que

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

    es equivalente a

    i=[ROW(A1:A5)]:v=i(1,1) ''#23 bytes
Greedo
fuente
Perdón por la publicación gigantesca, si alguien siente que puede hacer que las áreas sean más concisas / si tiene sugerencias para agregar, entonces siéntase libre. Además, aunque investigué algo de esto, se encontró una parte justa al experimentar en VBA, por lo que si detecta errores de sentir que falta algo, ¡no dude en comentar / editar en consecuencia!
Greedo
1
En realidad, la última sección sobre matrices está un poco apagada; se puede usar en la ventana inmediatai=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott el
@TaylorScott Para que pueda, no sabía que podía establecer / retener valores en variables que aún no estaban definidas, pero supongo que es porque todavía estoy familiarizado con los liners de la ventana Inmediato. Han actualizado en consecuencia
Greedo
¿Funciona esto con Match? Lo intenté, pero siempre devuelve errores. Sin embargo, estaba pasando una matriz en lugar de un rango.
seadoggie01
5

Combinar Nextdeclaraciones

Next:Next:Next

Puede condensarse hasta

Next k,j,i

donde los iteradores para los Forbucles son i, jy k- en ese orden.

Por ejemplo, el siguiente (69 Bytes)

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

Puede condensarse hasta 65 bytes.

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

Y en cuanto a cómo esto afecta el formato y la sangría, creo que el mejor enfoque para manejar esto es alinear la siguiente declaración con la declaración más externa. P.ej.

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

Reductora IfDeclaraciones

Al asignar una variable usando un condicional If ... Then ... Else verificación , puede reducir la cantidad de código utilizado al eliminar elEnd If al poner el cheque completo en una línea.

Por ejemplo, esto ( 37 caracteres):

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

Se puede reducir a esto ( 30 caracteres)

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

Si tiene más de un condicional anidado, también puede minimizarlos de esta manera:

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

Nota la : que le permite agregar más de una línea / comando dentro de unIf bloque.

En casos simples como este, por lo general, también puede eliminar la Elseconfiguración de la variable antes de la Ifverificación ( 25 caracteres):

c = a
If a < b Then c = b

Aún mejor, lo anterior se puede reducir aún más a esto utilizando la IIf()función ( 20 caracteres):

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

Reducir Range("A1") y Me gusta llamadas

Range("A1").Value(17 Bytes) y el más simple Range("A1")(11 Bytes) pueden reducirse a [A1](4 Bytes)

Taylor Scott
fuente
2
O, en general, el uso de []para reemplazar Evaluate()en VBA es mucho más versátil que solo las llamadas de rango. Por ejemplo, puede usarlo para reemplazar WorksheetFunction.FuncName(args)con just [FuncName(args)], como ?[SUMPRODUCT({1,3,5},{2,7,-1})]o el muy útil [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo
Greedo, esa es una funcionalidad increíblemente importante de la que no sabía que debías agregar esto como su propia respuesta.
Taylor Scott
1
Claro, escribiré algo en breve. Sí, Evaluate("str")o la taquigrafía [str]es muy poderosa en VBA, solo lo descubrí recientemente, ¡y supongo que también será útil para jugar al golf!
Greedo
Muy útil, lo suficiente como para volver a mis respuestas para ver si puedo eliminar mi bytecount por alguna de ellas.
Taylor Scott
3

Eliminar espacios

VBA se formateará automáticamente para agregar mucho espacio que realmente no necesita. Hay una respuesta sobre meta que tiene mucho sentido para mí por qué podemos descontar los bytes agregados mediante el formateo automático. Sin embargo, es importante verificar siempre que no haya eliminado demasiado. Por ejemplo, aquí hay una respuesta mía que se redujo casi un 22% simplemente eliminando espacios:

Versión 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

Versión reducida: (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

Si copia / pega la versión reducida en VBA, se expandirá automáticamente al original. Puedes jugar con dónde es válido eliminar espacios. Los que he encontrado hasta ahora parecen seguir el patrón donde se espera que VBA aparezca un cierto comando porque, sin él, no es un código válido. Aquí hay algunos que he encontrado hasta ahora:

  • Antes y después de cualquier operación matemática: +-=/*^etc.
  • Antes Toy Stepen un Forcomunicado:For x=-3To 3Step 0.05
  • En realidad, antes de cualquier palabra reservada ( To, &, Then, etc.) si está precedida por un literal, como un número, ), ?, %, etc.
  • Después de &al combinar cadenas:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • Después de las llamadas a funciones: If s=StrReverse(s)Then
  • Dentro de las llamadas a funciones: Replace(Space(28)," ",0)
Tostadas de
fuente
¿Cuál es la regla sobre los caracteres no espaciales agregados mediante el formateo automático? Algo como ?vs PrintVeo es aceptable, pero poner una declaración de tipo como &inmediatamente después de una variable, por ejemplo, Debug.?a&"z"da Debug.Print a&; "z". El ;carácter agregado es esencial para que se ejecute el código. ¿Todavía está permitido?
Greedo
2
@Greedo Lo veo como lo describió la meta respuesta : si puede copiarlo / pegarlo en el editor y el código se ejecutará, está bien. Es decir, si VBA agrega automáticamente el carácter al pegar el código, entonces está bien.
Tostada de ingeniero
1
@EngineerToast en realidad se puede colocar un byte más fuera de su ejemplo: If i=1 Then puede llegar a ser If i=1Then , ya que, como regla general, una palabra reservada que sigue un literal, ser que un número, ), ?,% , etc .., no necesitan ser separados por una espacio
Taylor Scott
1
@EngineerToast, también puede soltar un byte desde su tercer punto de viñeta, ya que puede soltar los espacios entre un )(o cualquier otro literal que no sea un número) y&
Taylor Scott el
3

Prepárate para Pixel Art

Pixel art es, con mucho, una de las áreas más fuertes de Excel, ya que no hay necesidad de construir un lienzo, ya que está allí para usted, todo lo que necesita hacer es hacer algunos pequeños ajustes

1) Haz las celdas cuadradas

Cells.RowHeight=48

o, Alternativamente, por 1 byte más, pero es mucho más fácil trabajar con

Cells.ColumnWidth=2

2) Colorea el rango necesario

Cualquier Rangeobjeto puede ser coloreado llamando

`MyRangeObj`.Interior.Color=`ColorValue`

Nota: esto puede y debe combinarse con otros trucos mencionados en este wiki, como los rangos de referencia mediante el uso de la []notación (p [A1:R5,D6]. Ej. ) Sobre el uso de una Cells(r,c)o una Range(cellAddress)llamada. Además, como se señaló en este wiki, esto se puede combinar con un valor de color negativo para reducir el tamaño de las referencias de color

Referencias rápidas

Referencia de rango

Se A1puede hacer referencia a la celda de cualquiera de las siguientes maneras

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

y se A1:D4puede hacer referencia al Rango de cualquiera de las siguientes maneras

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

Referencia de color

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

Simplifica las funciones integradas

Cuando use ciertas funciones con frecuencia, reasignelas a una función definida por el usuario.

El siguiente código ( 127 caracteres) se puede reducir 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

a ( 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 esto con el truco ByRef , puede guardar aún más caracteres (hasta 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

Haga esto juiciosamente, ya que VBA toma muchos personajes para definir a Function. El segundo bloque de código en realidad sería más grande que el primero con cualquier número de Format()llamadas menos .

Gaffi
fuente
2
en el último, no necesita la llamada de asignación, lo que significa que a = f(w)se puede reducir af w
Taylor Scott
3

STDIN y STDOUT

Ingreso a Subrutinas y Functions mediante variables de entrada

Public Sub A(ByRef B as String)

Puede reducirse a

Sub a(b$) 

los Public yByRef llamadas son las predeterminadas para VBA y, por lo tanto, son implícitas, y pueden (casi) siempre descartarse.

El tipo literal $ obliga ba ser del tipoString .

Otros literales tipo

  • ! Soltero
  • @ Moneda
  • # Doble
  • % Entero
  • $ Cuerda
  • & Largo
  • ^ LongLong (solo 64 bits)

Además, generalmente se acepta que puede dejar la variable de entrada como el tipo predeterminado, Varianty dejar los errores basados ​​en el tipo sin controlar. P.ej. Sub E(F)en el que Fse espera que sea de tipo Boolean[](que se pasaría a la rutina comoE Array(True, False, False) )

Ingresando a Sub rutinas y funciones de ventana inmediata a través deCells

VBA no tiene una consola completamente funcional y, por lo tanto, no tiene ningún STDIN oficial , y por lo tanto permite algunos juego con el paso de entrada.

En Excel, generalmente se acepta tomar datos de una celda o rango de celdas, lo que se puede hacer como

s=[A1]

que implícitamente pone el .valuede la celda [A1](que también puede ser referenciado como cells(1,1)orange("A1")

Problema de ejemplo: mostrar la entrada en un cuadro de mensaje

Vía subrutina Sub A:msgbox[A1]:End Sub

Vía Función de ventana inmediata msgbox[A1]

Ingreso a través de argumentos de compilación condicional

Los proyectos de VBA admiten la toma de argumentos desde la línea de comandos o mediante las propiedades de VBAProject (ver a través del explorador de proyectos -> [Su proyecto de VBA] - (Clic derecho) -> Propiedades de VBAProject -> Argumentos de compilación condicional)

Esto es en gran medida útil para los desafíos de código de error

Dado el argumento de compilación condicional n=[some_value], esto permite ejecutar código que producirá un código de error, basado en el valor de n. tenga en cuenta que esto requiere una adición de 2 bytes a su código para la n=sección de argumentos de compilación condicional del Panel de propiedades de VBAProject.

Código de ejemplo

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

Salida a través del valor de la función

No hay mucho que decir aquí, la forma general de citada a continuación es tan compacta como se puede hacer.

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

NOTA: en la gran mayoría de los casos, es más byte convertir el método a una subrutina y enviarlo a la ventana de VBE inmediata (ver más abajo)

Salida desde Subrutinas Functionys a través de la ventana Inmediatos de VBE

La salida a la ventana de inmediatos de VBE (también conocida como la ventana de depuración de VBE) es un método de salida común para VBA para desafíos basados ​​en texto, sin embargo, es importante recordar que la Debug.Print "Text"llamada puede ser sustancialmente mejorada.

Debug.Print "Text"

es funcionalmente idéntico a

Debug.?"Text"

como ?autoformatos para Print.

Salida de Subrutinas y funciones de la ventana Inmediato de VBE a través de otros métodos

En raras ocasiones, cuando la situación es correcta, puede recibir información de algunas de las entradas más triviales disponibles para VBA, como el ajustador de tamaño de fuente, el selector de fuente y el zoom. (Por ejemplo, emular el selector de tamaño de fuente de Word )

Taylor Scott
fuente
2

Nota rápida sobre formateo

Porque StackExchange usa Markdown y Prettify.js , es posible agregar un indicador de idioma a sus respuestas de codificación, lo que generalmente las hace ver más profesionales. Si bien no puedo garantizar que esto te hará mejorar en el golf en VBA, sí puedo garantizar que te hará ver como eres.

Agregar cualquiera de las siguientes banderas transformará

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

a

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

Etiquetas de lenguaje VBA

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

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

Nota: el último transforma todos los segmentos de código en su respuesta, mientras que el anterior solo transforma los segmentos de código que siguen inmediatamente

Taylor Scott
fuente
lang-vbeh? - Es extraño que eso formatee mejor que lang-vbapara las respuestas vba.
Greedo
1
@Greedo, eso se debe a que lang-vbasi bien proporcionará resaltado, en realidad es solo el resaltado predeterminado. Aparentemente, VBA no se ha implementado realmente en Prettify.js, por lo que tendremos que seguir con el resaltado de VB
Taylor Scott
2

Múltiples If .. Thencontroles

Como en otros idiomas, múltiples Ifcontroles generalmente se pueden combinar en una sola línea, lo que permite el uso de And/ Or(es decir &&/ ||en C y otros), que en VBA sustituye a la vez una Theny unaEnd If .

Por ejemplo, con un condicional anidado ( 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

puede convertirse ( 69 caracteres):

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

Esto también funciona con condicionales no anidados.

Considere ( 84 caracteres):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Esto puede convertirse ( 51 caracteres):

If a = b Or c = b Then            
    d = 0
End If
Gaffi
fuente
1
en las declaraciones If - then, la parte "End - if" es opcional siempre que escriba el código en una sola línea.
Stupid_Intern
@newguy Correcto. Consulte también esta otra respuesta: codegolf.stackexchange.com/a/5788/3862
Gaffi
La declaración anterior se puede resumir aún más end=iif(a=b or c=b,0,d)
Taylor Scott
2

terminando ForLoops

Al usar Forbucles, unNext línea no necesita un nombre de variable (aunque probablemente sea mejor usarla en la codificación normal).

Por lo tanto,

For Variable = 1 to 100
    'Do stuff
Next Variable

se puede acortar a:

For Variable = 1 to 100
    'Do stuff
Next

(Los ahorros dependen de su nombre de variable, aunque si está jugando al golf, probablemente sea solo 1 carácter + 1 espacio).

Gaffi
fuente
1
¡2 personajes, no te olvides de contar el espacio!
11684
¡Casi nunca identifico la variable, incluso en código normal!
dnep
2

Dividir una cadena en una matriz de caracteres

A veces puede ser útil separar una cadena en caracteres individuales, pero puede tomar un poco de código hacer esto manualmente en 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

En cambio, puede usar una sola línea, una cadena de funciones relativamente mínima para hacer el trabajo:

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

Esto asignará su cadena sa la Variantmatriz a. Sin embargo, tenga cuidado, ya que el último elemento de la matriz será una cadena vacía ( ""), que deberá manejarse adecuadamente.

Así es como funciona: la StrConvfunción convierte a Stringa otro formato que especifique. En este caso, 64 = vbUnicode, por lo que se convierte a un formato unicode. Cuando se trata de cadenas ASCII simples, el resultado es un carácter nulo (no una cadena vacía,"" ) insertado después de cada carácter.

Lo siguiente Splitconvertirá el resultado Stringen una matriz, utilizando el carácter nulo Chr(0)como delimitador.

Es importante tener en cuenta que Chr(0)no es lo mismo que la cadena vacía "", y usar Spliton ""no devolverá la matriz que podría esperar. Lo mismo también es cierto para vbNullString(pero si estás jugando al golf, ¿por qué usarías una constante tan detallada en primer lugar?).

Gaffi
fuente
Debe mencionar que la matriz resultante tiene una cadena vacía adicional al final.
Howard
@Howard Sí, debería. Estaba en mi cabeza mientras escribía esto, debe haberme olvidado.
Gaffi
2

Uso With(¡A veces! Ver nota al pie)

El uso de la Withdeclaración puede reducir el tamaño de su código significativamente si usa algunos objetos repetidamente.

es decir, esto ( 80 caracteres):

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

puede codificarse como ( 79 caracteres):

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

Lo anterior ni siquiera es el mejor de los casos. Si usa algo con Application, como Excel.Applicationdesde Access, la mejora será mucho más significativa.


* Dependiendo de la situación, Withpuede o no ser más eficiente que esto ( 64 caracteres):

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

Bucles infinitos

Considere reemplazar

Do While a<b
'...
Loop

o

Do Until a=b
'...
Loop

con el anticuado pero menor recuento de bytes

While a<b
'...
Wend

Si necesita salir Subo Functionprematuramente, en lugar deExit ...

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

considerar End

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

Tenga en cuenta que Enddetiene toda la ejecución de código y borra las variables globales, así que use con prudencia

Greedo
fuente
Debería considerar reescribir la última sección ( Fory End) para reflejar que el caso 100nunca se resolverá y agrega un byte innecesario
Taylor Scott
Además, si bien esto es muy legible, puede considerar eliminar el espacio en blanco para mostrar mejor los posibles beneficios de estos métodos (siempre es bueno abusar del autoformato en VBA para codegolfing)
Taylor Scott
2

Utilizar Spc(n)más Space(n), [Rept(" ",n)]oString(n," ")

Cuando intente insertar varios espacios de longitud n, use

Spc(n)              ''  6  bytes

terminado

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

Nota: No estoy seguro de por qué, pero parece que no puede asignar la salida de Spc(n)una variable, y que debe imprimirse directamente, por lo que en ciertos casos Space(n)sigue siendo la mejor manera de hacerlo.

Taylor Scott
fuente
2

Reduce Debug.Printy Printllama

Debug.Print [some value] 

(12 bytes; tenga en cuenta el espacio final) puede reducirse a

Debug.?[some value]

(7 bytes; tenga en cuenta la falta de espacio final).

Similar,

Print 

(6 bytes) puede reducirse a

?

(1 byte).

Además, cuando se opera en el contexto de una función de ventana inmediata anónima de VBE, la Debugdeclaración se puede descartar por completo, y en su lugar ?se puede suponer que la impresión en la ventana inmediata de VBE es STDIN / STDOUT

Caracteres especiales

Al imprimir cadenas también puede usar caracteres especiales en lugar de &. Estos permiten formatos alternativos en lo que se imprime o eliminación de espacios en blanco

Para unir cadenas variables, en lugar de

Debug.Print s1 &s2

Puedes usar un punto y coma ;

Debug.?s1;s2

Este punto y coma es el comportamiento predeterminado para cadenas consecutivas, siempre que no haya ambigüedad. Por lo tanto, estos son válidos:

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

Pero 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

Tenga en cuenta que a; al final de una línea suprime una nueva línea, ya que las nuevas líneas se agregan por defecto después de cada impresión. El conteo de bytes devueltos por el código VBA está en debate

Para unirse con una pestaña use una coma ,(en realidad 14 espacios, pero según)

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

Finalmente, puede usar declaraciones de tipo para unir cadenas en lugar de; cada una tiene su propio ligero efecto en el formateo. Para todo lo que sigue a = 3.14159es la primera línea

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

Use un ayudante SubparaPrint

Si el código requiere el uso de más de seis Debug.? declaraciones, puede reducir los bytes reemplazando todos los Depuración. líneas con una llamada a un Sub como el de abajo. Para imprimir una línea en blanco, debe llamar p ""ya que se requiere un parámetro.

Sub p(m)
Debug.?m
End Sub
Ben
fuente
1
Para imprimir una nueva línea con que usted sólo necesita p""o si puede ser sin terminar, p". Sin embargo, en la gran mayoría de los casos en los que esto puede aplicarse, tiene más sentido usar una variable de cadena y solo imprimir la variable de cadena al final.
Taylor Scott
1

Usar en Array() Choose()lugar de SelectoIf...Then

Al asignar una variable basada en el valor de otra variable, tiene sentido escribir los pasos con If...Thencheques, así:

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

Sin embargo, esto puede ocupar mucho espacio de código si hay más de una o dos variables para verificar (de todos modos, en general todavía hay mejores maneras de hacerlo).

En cambio, la Select Casedeclaración ayuda a reducir el tamaño de los cheques al encerrar todo en un bloque, así:

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

Esto puede conducir a un código mucho más pequeño, pero para casos muy simples como este, existe un método aún más eficiente: Choose()esta función seleccionará un valor de una lista, en función del valor que se le pase.

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

La opción para seleccionar ( aen este caso) es un valor entero pasado como primer argumento. Todos los argumentos posteriores son los valores para elegir (1 indexado, como la mayoría de VBA). Los valores pueden ser de cualquier tipo de datos siempre que coincidan con la variable establecida (es decir, los objetos no funcionan sin la Setpalabra clave) e incluso pueden ser expresiones o funciones.

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

Una opción adicional es usar la Arrayfunción para obtener el mismo efecto mientras se guarda otro personaje:

b = Array(5 + 4, String(7,"?"))(a)
Gaffi
fuente
Un uso interesante y posiblemente muy beneficioso para el golf es usar esto junto con uno IIf()u otro 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 con desplazamiento de bits

Debido a la forma en que Excel maneja los colores, (entero hexadecimal de 6 caracteres sin signo) puede usar enteros con signo negativo, de los cuales Excel solo usará los 6 bytes correctos para asignar un valor de color

Esto es un poco confuso, por lo que a continuación se proporcionan algunos ejemplos.

Digamos que desea utilizar el color blanco, que se almacena como

rgbWhite

y es equivalente a

&HFFFFFF ''#value: 16777215

para reducir esto todo lo que tenemos que hacer es encontrar un valor hexadecimal negativo que termine en FFFFFFy dado que los valores hexadecimales negativos deben estar en el formato de FFFFXXXXXX(tal que Xsea ​​un hexadecimal válido) contando desde FFFFFFFFFF( -1) hasta FFFF000001( -16777215)

Sabiendo esto podemos generalizar que la fórmula

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

Usando esto, algunas conversiones útiles son

rgbWhite = &HFFFFFF = -1 
rgbAqua  = &HFFFF00 = -256
16747627 = &HFF8C6B = -29589
Taylor Scott
fuente
Es bueno saber qué estaba pasando allí, lo descubrí por accidente en esa pregunta, pero esta explicación clara muestra exactamente cómo funciona. Otra cosa a tener en cuenta es que ciertos colores clave se pueden reducir con operadores matemáticos; rgbWhite= 2^24-1aunque posiblemente podría reducirse aún más si se pierde el -1 para llegar más o menos allí
Greedo
1
De hecho, aquí hay una lista de colores con sus representaciones matemáticas, que son más cortas que las versiones decimales positivas o negativas: &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 no necesariamente completo, pero creo que hice un trabajo bastante exhaustivo
Greedo
1

Omitir terminal " al imprimir en Ventana Inmediata

Dada la función a continuación, que se utilizará en la ventana de depuración

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

La Terminal "puede dejarse caer por -1 Byte, dejando la cadena sin cerrar y el programa ejecutará lo mismo, sin error

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

Aún más sorprendente que esto es que esto se puede hacer dentro de subrutinas completamente definidas.

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

La subrutina anterior se ejecuta como se esperaba y los autoformatos para

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

Utilice las variables Truthy y Falsey en condicionales

A veces se llama conversión implícita - directamente a través de un tipo de número en una If, [IF(...)]o IIf(...)declaración, mediante el uso de la naturaleza y Truthy Falsey- de ese número puede absolutamente salvarte algunos bytes.

En VBA, cualquier variable de tipo de número que no sea cero se considera verdadera (y, por lo tanto, cero 0, es el único valor falsey) y, por lo tanto,

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

puede condensarse a

If B Then C=B Else C=D

y más allá de

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

Hojas de direcciones por nombre

En lugar de direccionar un WorkSheetobjeto llamando

Application.ActiveSheet
''  Or 
ActiveSheet   

Uno puede usar

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

O más preferiblemente, uno puede acceder al objeto directamente y usar

Sheet1
Taylor Scott
fuente
1

Exponenciación y LongLongs en VBA de 64 bits

La forma general de exponenciación,

A to the power of B

Se puede representar como en VBA como

A^B 

Pero solo en las instalaciones de Office de 32 bits , en las instalaciones de Office de 64 bits, la forma más corta que puede representar sin error es

A ^B

Esto se debe a que en las versiones de 64 bits de VBA ^sirve tanto el literal de exponenciación como el LongLongcarácter de declaración de tipo . Esto significa que puede surgir una sintaxis válida pero de aspecto extraño, como

a^=2^^63^-1^

que asigna variable apara mantener el valor máximo de unLonglong

Taylor Scott
fuente
1

Comprimir matrices de bytes como cadena

Para los desafíos que requieren que la solución contenga datos constantes, puede ser útil comprimir esos datos como una sola cadena y luego iterar a través de la cadena para obtener los datos.

En VBA, cualquier valor de byte se puede convertir directamente a un carácter con

Chr(byteVal)

Y un valor longo integerpuede convertirse a dos caracteres con

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

Entonces, para una bytematriz, un algoritmo de compresión se vería algo así

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 la Select Casesección se implementa debido a los caracteres que no pueden almacenarse como literales en la cadena.

De la cadena resultante, que se verá algo así

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

Los datos se pueden extraer utilizando las funciones Ascy Mid, p. Ej.

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

Usar constantes impropias

VBA permite, en algunos casos, el uso de constantes no listadas o impropias en expresiones que requieren valores constantes. A menudo, estos son valores heredados y tienen una longitud más corta que los valores adecuados.

Por ejemplo, los valores a continuación se pueden usar cuando se deja que la rng.HorizantalAlignmentpropiedad mantenga un valor .

IncorrectoApropiadoConstante generalxlHAlign  Constante11xlGeneralxlHAlignGeneral2-4131xlizquierdaxlHAlignLeft3-4108xlCenterxlHAlignCenter4 4-4152xlRightxlHAlignRight5 55 5xlFillxlHAlignFill6 6-4130xlJustifyxlHAlignJustify7 77 7xlCenterAcrossSelectionxlHAlignCenterAcrossSelection8-4117xlDistribuidoxlHAlignDistributed

Esto significa, por ejemplo, que configurar una celda para centrar su texto con

rng.HorizantalAlignment=-4108

puede acortarse a

rng.HorizantalAlignment=3

reemplazando el valor constante incorrecto 3por el valor apropiado -4108. Tenga en cuenta que si obtiene el rng.HorizantalAlignmentvalor de la propiedad, devolverá el valor adecuado. En este caso, eso sería -4108.

Taylor Scott
fuente
1

En Excel, cree matrices numéricas coaccionando rangos

Cuando un conjunto constante unidimensional de números de longitud mixta, Ses necesario, será más eficiente usar [{...}]notación para declarar un rango y luego forzarlo en una matriz numérica en lugar de usar la Split(String)notación o similar.

Usando este método, un cambio de Δrecuento de bytes=-5 5 bytes se devengará para todos S.

Ejemplo

Por ejemplo,

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

puede escribirse como

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

Vale la pena señalar que, si bien este método no permite la indexación directa, sí permite la iteración sobre el ciclo for directamente, es decir

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