Советы по игре в гольф в VBA


16

Подобно этому , этому и этому вопросу ...

Какие общие советы у вас есть для игры в гольф VBA? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, по крайней мере, несколько специфичны для них VBA(например, «удалить комментарии» - это не ответ). Пожалуйста, оставьте один совет за ответ.

Хотя я работал с другими языками, я сильнейший VBA, и я не вижу много игроков в гольф, использующих VBAна этом сайте.


Преобразуется в вики сообщества в соответствии с политикой.
dmckee

Извините, это не было автоматическим с моей стороны!
Gaffi

Нет проблемы. На самом деле, они отобрали у CW вопросы от пользователей (я думаю, вы все еще можете делать ответы). Вы можете пометить внимание модератора, но такая малая активность, как CodeGolf, вряд ли необходима.
dmckee

2
VBA - относительно многословный язык с несколькими синтаксическими ярлыками. Если вы стремитесь к лучшему результату, VBA может быть не лучшим выбором. Если вы хотите отточить свои навыки, больше сил для вас.
Мистер Лама

2
@GigaWatt Хонинг мои навыки это. На самом деле, с тех пор, как я поиграл с разными проблемами, я уже подобрал несколько новых приемов для работы с VBA! Я не ожидаю выиграть какие-либо реальные соревнования по коду с VBA, но это хорошая практика. :-)
Gaffi

Ответы:


8

Использование по ByRefумолчанию при вызове подпрограмм

Иногда можно использовать Subвызов вместо a, Functionчтобы сохранить несколько дополнительных символов ...

Это ( 87 символов)

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

может быть переработано до ( 73 символа):

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

Обратите внимание, что это НЕ будет зацикливаться вечно, хотя кажется, что вы никогда не переназначаете bзначение.

Вышеупомянутое не использует Functionвызов, но вместо этого использует функциональность ByRef(«По ссылке») Subвызова. Это означает, что переданный аргумент - это та же переменная, что и в вызывающей функции (в отличие от ByValпередачи «По значению», которая является копией). Любые изменения переданной переменной будут преобразованы обратно в вызывающую функцию.

По умолчанию принимает все аргументы как ByRef, поэтому нет необходимости использовать символы для определения этого.

Приведенный выше пример может не совсем идеально подходить для вас, в зависимости от возвращаемого значения вашей функции. (т.е. возвращает тип данных, отличный от передаваемого), но это также позволяет получить возвращаемое значение, в то же время изменяя исходную переменную.

Например:

Sub a()
b = 0
Debug.Print c(b) ' This will print 0, and b will equal 1.'
End Sub
Function c(d)
c = d
d = d + 1
End Function

7

Напишите и запустите код VBA в Немедленном окне

Непосредственное окно оценивает любой допустимый исполняемый оператор VBA. Просто введите оператор в Immediate Window, как в редакторе кода. Он быстро выполняет код VBA и может сохранить много дополнительных символов, потому что:

  1. Помещение вопросительного знака (?) В начале оператора говорит Немедленному окну отображать результат вашего кода.

введите описание изображения здесь

  1. Вам не нужно использовать Sub и End Sub в вашем коде.

введите описание изображения здесь


Вот пример кода VBA в Immediate Window, чтобы ответить на сообщение PPCG с тегом : Буква A без A

?Chr(88-23);

ответил Джоффан .


Кредитные изображения: Excel Campus


1
Это использует среду REPL хотя? Это означает, что это всего лишь фрагмент, а не программа или функция
caird coinheringaahing

Я думаю, что другим примером для добавления может быть то, что вы также можете создавать переменные inline; Например, a="value":?aсначала устанавливает значение a, а затем печатает его.
Greedo

6

Условные проверки перед циклом

Некоторые условные проверки являются избыточными при использовании в сочетании с циклами. Например, Forцикл не будет обрабатываться, если начальное условие находится за пределами рабочего состояния.

Другими словами, это ( 49 символов):

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

Можно превратить в это ( 24 символа):

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

Комментарий внизу неверен. Если B = 0, то цикл будет введен. pastebin.com/97MBB7hq
QHarr

5

Объявление переменной

В большинстве случаев в VBA вы можете пропустить Option Explicit(по крайней мере, часто по умолчанию опущены) и пропустить Dimмногие из ваших переменных.

При этом, это ( 96 символов):

Option Explicit

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

Становится так ( 46 символов):

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

Если вам нужно использовать определенные объекты (например, массивы), вам все равно может понадобиться Dimэта переменная.


Подождите секунду, вы приняли свой ответ на свой вопрос. Не круто, чувак.
Тейлор Скотт

1
@TaylorScott Это вики-пост - без баллов, и в этом случае нет ни одного лучшего ответа. :) Я принимаю ответ ~ 5 лет назад, чтобы в моем списке вопросов не было флажка.
Гаффи

1
@TaylorScott также, если вы принимаете свой собственный ответ, вы не получите +15 или +2 (за принятие)
caird coinheringaahing

5

Evaluate() И []

Как указывалось ранее, жестко закодированные диапазоны вызовов могут быть сокращены с помощью записи в квадратных скобках [A1]. Однако он имеет гораздо больше применений, чем просто это.

Согласно документации MSDN , Application.Evaluate()метод принимает один аргумент, который является Nameопределенным соглашением об именах Microsoft Excel.

NB [string]- сокращение Evaluate("string")(обратите внимание на ""речевые метки, обозначающие тип данных строки), хотя есть несколько важных различий, которые рассматриваются в конце.

Так что же все это означает с точки зрения использования?

По сути, [some cell formula here]представляет собой ячейку на листе Excel, и вы можете поместить в нее практически все, что угодно, и извлечь из нее все, что могли бы с обычной ячейкой.

Что входит в

В итоге, с примерами

  • Ссылки в стиле А1. Все ссылки считаются абсолютными ссылками.
    • [B7] возвращает ссылку на эту ячейку
    • Поскольку ссылки являются абсолютными, ?[B7].Addressвозвращается"B$7$"
  • Диапазоны Вы можете использовать операторы range, intersect и union (двоеточие, пробел и запятая соответственно) со ссылками.
    • [A1:B5]возвращает ссылку на A1:B5диапазон (Range)
    • [A1:B5 A3:D7]возвращает ссылку на диапазон A3:B5(Пересечь)
    • [A1:B5,C1:D5]возвращает ссылку на диапазон A1:D5(технически A1:B5,C1:D5) (объединение)
  • Определенные имена
    • Определяется пользователем, например, [myRange]ссылаясь на A1: G5
    • Автоматический, как имена таблиц [Table1](возможно, менее полезен для codegolf)
    • Все остальное вы можете найти в меню [Formulas]>[Name Manager]
  • Формулы
    • Очень полезно ; любая формула, которая может войти в клетку, может войти Evaluate()или[]
    • [SUM(1,A1:B5,myRange)]возвращает арифметическую сумму значений в диапазонах myRange здесь относится к имени книги, а не к переменной VBA
    • [IF(A1=1,"true","false")](1 байт короче, чем эквивалент VBA Iif([A1]=1,"true","false"))
    • Формулы массива [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]- объединяет все строки в диапазоне, длина которого больше 2 с пробелом
  • Внешние ссылки
    • Вы можете использовать !оператор для ссылки на ячейку или на имя, определенное в другой книге.
    • [[BOOK1]Sheet1!A1]возвращает ссылку на диапазон A1 в BOOK1 или ['[MY WORKBOOK.XLSM]Sheet1!'A1]для того же самого вMY WORKBOOK
    • Обратите внимание 'на книги с пробелами в их именах и отсутствие расширения для именованных книг по умолчанию ( BOOK+n)
  • Объекты диаграммы (см. Статью MSDN)

NB Я задал вопрос о SO для этой информации, так что посмотрите там для лучшего объяснения

Что выходит

Подобно тому, что входит, то, что выходит, включает в себя все, что может вернуть ячейка рабочего листа. Это стандартные типы данных Excel (и их эквиваленты VBA):

  • Логический ( Boolean)
  • Текст ( String)
  • Числовой ( Double)
  • Error ( Variant/Error) (это неустранимые ошибки, т. Е. Они не останавливают выполнение кода, ?[1/0]выполняется нормально)

Но есть несколько вещей, которые могут быть возвращены, которые ячейки не могут:

  • Диапазон ссылки ( Range) (см. Выше разделы)
  • Массивы ( Variant())

Массивы

Как было показано, []может использоваться для оценки формул массива, которые возвращают один из стандартных типов данных Excel; например, [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]который возвращается Text. Однако Evaluateможет также возвращать массивы Variantтипа. Это может быть

HARDCODED:

[{1,2;3,4}]- выводит двумерный массив: ,является разделителем столбцов, ;разделяет строки. Может вывести 1D массив

Формулы массивов:

[ROW(A1:A5)]- выводит двумерный массив {1,2,3,4,5}, т.е. (2,1) является вторым элементом (но некоторые функции выводят одномерные массивы)

  • По какой-то причине некоторые функции не возвращают массивы по умолчанию

[LEN(A1:A5)] выводит только длину текста в 1-й ячейке диапазона

  • Тем не менее, они могут быть приведены к массивам

Split([CONCAT(" "&LEN(A1:A5))]) дает 1D массив от 0 до 5, где первый элемент пуст

[INDEX(LEN(A1:A5),)]Это еще один обходной путь, по сути, вы должны использовать функцию обработки массива, чтобы получить желаемое поведение возврата массива, аналогично добавлению бессмысленного, RAND()чтобы сделать формулы вашего листа нестабильными.

  • Я задал вопрос о SO, чтобы попытаться получить более подробную информацию об этом, пожалуйста, отредактируйте / прокомментируйте с лучшими параметрами, если вы их найдете

Evaluate() против []

Есть несколько различий между Evaluate()и []быть в курсе

  1. Строки против жестко
    • Пожалуй, самое важное отличие, Evaluate принимает строковый ввод, где [] требуется жестко закодированный ввод
    • Это означает , что ваш код может создать строку с переменными , например , Evaluate("SUM(B1,1,"&v &",2)")будет подводить [B1], 1, 2и переменныйv
  2. Массивы

    При возврате массива можно использовать только Evaluate с индексом массива, поэтому

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

    эквивалентно

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

Извините за гигантский пост, если кто-то считает, что может сделать области более лаконичными / если у вас есть советы по добавлению, то не стесняйтесь. Кроме того, хотя я и исследовал некоторые из них, при экспериментировании в VBA была найдена немалая часть, поэтому, если вы заметите, что что-то упущено, не стесняйтесь комментировать / редактировать соответственно!
Greedo

1
На самом деле, последний раздел о массивах немного отключен - его можно использовать в ближайшем окнеi=[ROW(A1:A5)]:v=i(2,1):?v
Тейлор Скотт,

@TaylorScott Итак, вы можете, я совершенно не знал, что вы можете устанавливать / хранить значения в переменных, которые еще не были определены, но я полагаю, что это потому, что я все еще справляюсь с 1-сторонними строками Immediate window.
Greedo

Это работает с Match? Я пытался, но он всегда возвращает ошибки. Я передавал массив вместо диапазона, хотя.
seadoggie01

5

Объединить Nextзаявления

Next:Next:Next

Может быть сжат до

Next k,j,i

где итераторы для Forпетель i, jиk - в таком порядке.

Например, ниже (69 байт)

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

Может быть сжат до 65 байт

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

А что касается того, как это влияет на форматирование и отступ, я думаю, что лучший подход к обработке этого вопроса - это выравнивание следующего оператора с внешним большинством для оператора. Например.

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

4

Снижение If Заявления

При назначении переменной с помощью условного If ... Then ... Else проверки вы можете уменьшить объем используемого кода, исключивEnd If , поместив всю проверку в одну строку.

Например, это ( 37 символов):

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

Может быть уменьшено до этого ( 30 символов)

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

Если у вас есть несколько вложенных условных выражений, вы также можете минимизировать их следующим образом:

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

Обратите внимание : позволяет добавить более одной строки / команды в пределахIf блоке.

В таких простых случаях, как это, вы можете также удалить Else, установив переменную перед Ifпроверкой ( 25 символов):

c = a
If a < b Then c = b

Более того, вышесказанное может быть дополнительно сведено к этому с помощью IIf()функции ( 20 символов):

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

3

Уменьшить Range("A1")и как звонки

Range("A1").Value(17 байт) и более простой Range("A1")(11 байт) могут быть уменьшены до [A1](4 байт)


2
Или вообще, использование []замены Evaluate()в VBA намного более универсально, чем просто вызовы диапазона. Например, вы можете использовать его, чтобы заменить WorksheetFunction.FuncName(args)просто [FuncName(args)], например, ?[SUMPRODUCT({1,3,5},{2,7,-1})]или очень полезно [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Гридо, это невероятно важный функционал, о котором я не знал, что ты должен добавить это в качестве своего собственного ответа.
Тейлор Скотт

1
Конечно, я напишу что-нибудь в ближайшее время. Да Evaluate("str")или стенография [str]очень сильна в VBA, я только недавно узнал, и я думаю, что это будет полезно и для игры в гольф!
Greedo

Очень полезно, настолько, что я возвращаюсь к своим ответам, чтобы посмотреть, смогу ли я оставить свой счет по любому из-за этого
Тейлор Скотт,

3

Удалить пробелы

VBA будет автоматически форматировать, чтобы добавить большой интервал, который на самом деле не нужен. Есть ответ на мета, который имеет большой смысл для меня, почему мы можем дисконтировать байты, добавленные автоматическим форматированием. Важно всегда проверять, что вы не удалили слишком много. Например, вот мой ответ, который был уменьшен почти на 22% только за счет удаления пробелов:

Оригинальная версия: (188 байт)

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

Уменьшенная версия: (146 байт)

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

Если вы скопируете / вставите уменьшенную версию в VBA, она автоматически расширится до оригинала. Вы можете поиграть с тем, где это допустимо, чтобы удалить пробелы. Те, которые я нашел до сих пор, похоже, следуют шаблону, в котором от VBA ожидается появление определенной команды, потому что без нее это недопустимый код. Вот некоторые, которые я нашел до сих пор:

  • До и после любой математической операции: +-=/*^ и т. Д.
  • До Toи StepвFor заявлении:For x=-3To 3Step 0.05
  • На самом деле, перед любым зарезервированным словом ( To, &, Thenи т.д.) , если он предшествует буквальным , например, номер, ), ?,% и т.д.
  • После & объединения строк:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • После вызова функции: If s=StrReverse(s)Then
  • Внутри вызовов функций: Replace(Space(28)," ",0)

Каково правило для добавленных непробельных символов через автоформатирование. Что-то вроде ?vs, которое Printя вижу, приемлемо, но &добавление объявления типа, как сразу после переменной, например, Debug.?a&"z"дает Debug.Print a&; "z". Добавленный ;символ необходим для запуска кода - это все еще разрешено?
Greedo

2
@Greedo Я вижу, как мета-ответ описал это: если вы можете скопировать / вставить его в редактор, и код запустится, все в порядке. То есть, если VBA автоматически добавляет символ обратно при вставке кода, то все в порядке.
Тост инженера

1
@EngineerToast вы можете упасть еще один байт от вашего примера: If i=1 Then может стать , If i=1Then потому что, как правило , зарезервированное слово , которое следует буквальным, будь то число, ), ?, %, .. и т.д., не должны быть отделены друг от друга пространство
Тейлор Скотт

1
@EngineerToast, вы также можете отбросить байт из своей третьей точки маркера, поскольку вы можете отбросить пробелы между )(или любым другим нечисловым литералом) и&
Тейлор Скотт

3

Подготовьтесь к пиксельной графике

Пиксельная графика - одна из самых сильных сторон Excel, так как нет необходимости создавать холст, так как он уже есть у вас - все, что вам нужно сделать, это сделать небольшие корректировки

1) Сделайте клетки квадратными

Cells.RowHeight=48

или, как вариант, на 1 байт больше, но с ним гораздо проще работать

Cells.ColumnWidth=2

2) Раскрась нужный диапазон

Любой Rangeобъект может быть окрашен с помощью вызова

`MyRangeObj`.Interior.Color=`ColorValue`

Примечание: это можно и нужно сочетать с другими приемами, отмеченными в этой вики, такими как ссылки на диапазоны с помощью []нотации (например [A1:R5,D6]) над использованием a Cells(r,c)или aRange(cellAddress) вызова. Кроме того, как отмечено в этой вики, это может быть объединено с отрицательным значением цвета для уменьшения размера эталонных цветов.

Быстрые ссылки

Диапазон Ссылка

На ячейку A1можно ссылаться любым из следующих способов

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

и на диапазон A1:D4можно ссылаться любым из следующих способов

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

Цветовой справочник

Black  0
White  -1
Red    255
Aqua   -256

3

Упростите встроенные функции

При частом использовании определенных функций переназначайте их пользовательской функции.

Следующий код ( 127 символов) может быть уменьшен с:

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 символа):

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

Комбинируя это с трюком ByRef , вы можете сохранить еще больше символов (до 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

Делайте это разумно, так как VBA требует много символов для определения Function. Второй кодовый блок будет на самом деле больше первого при любом количестве Format()вызовов.


2
в последнем вам не нужен вызов присваивания, то есть a = f(w)его можно уменьшить доf w
Тейлор Скотт

3

STDIN и STDOUT

Ввод в Subподпрограммы и Functions через входные переменные

Public Sub A(ByRef B as String)

Может быть уменьшено до

Sub a(b$) 

PublicиByRef звонки по умолчанию для VBA и , таким образом , неявно, и может (почти) всегда быть отброшен.

Тип буквальный $заставляет bбыть типаString .

Другие литералы типа

  • ! не замужем
  • @ валюта
  • # двойной
  • % целое число
  • $ строка
  • & Длинная
  • ^ LongLong (только 64 бит)

Кроме того, общепринято, что вы можете оставить входную переменную в качестве типа по умолчанию Variantи оставить любые ошибки на основе типов необработанными. Например. Sub E(F)в котором, Fкак ожидается, будет иметь тип Boolean[](который будет передан в рутину, какE Array(True, False, False) )

Ввод в Sub подпрограммы и функции непосредственного окна черезCells

VBA не имеет полностью функциональной консоли и, следовательно, не имеет никакого официального STDIN, и, следовательно, позволяет некоторые игру с передачей ввода.

В Excel, как правило, принято принимать данные из ячейки или диапазона ячеек, что может быть сделано как

s=[A1]

который неявно помещает .valueиз ячейки [A1](на которую также можно ссылаться как cells(1,1)илиrange("A1")

Пример проблемы: отображение ввода в окне сообщения

Через подпрограмму Sub A:msgbox[A1]:End Sub

Через функцию окна Immediates msgbox[A1]

Ввод с помощью аргументов условной компиляции

Проекты VBA поддерживают получение аргументов из командной строки или через свойства VBAProject (просмотр через проводник проекта -> [Ваш проект VBA] - (Правый клик) -> Свойства VBAProject -> Аргументы условной компиляции)

Это в значительной степени полезно для вызовов кода ошибок

Учитывая аргумент n=условной компиляции [some_value], это позволяет выполнять код, который будет выдавать код ошибки, основанный на значении n. обратите внимание, это требует добавления 2-х байтов к вашему коду n=в разделе аргументов условной компиляции панели свойств VBAProject.

Пример кода

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

Вывод через значение функции

Не очень, чтобы сказать здесь, общая форма, приведенная ниже, настолько компактна, насколько это возможно.

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

ПРИМЕЧАНИЕ: в подавляющем большинстве случаев метод преобразования байта в подпрограмму и его вывод в окно немедленного использования VBE выполняется более подробно (см. Ниже).

Вывод из Subподпрограмм и Functions через окно VBE Immediates

Вывод в окно немедленного использования VBE (AKA - окно отладки VBE) является распространенным методом вывода для VBA для текстовых задач, однако важно помнить, что Debug.Print "Text"вызов может быть в значительной степени обработан.

Debug.Print "Text"

функционально идентичен

Debug.?"Text"

в качестве ?автоформатов Print.

Вывод из Subподпрограмм и функций окна VBE Immediates с помощью других методов

В редких случаях, когда ситуация просто правильная, вы можете использовать входные данные из некоторых более тривиальных входов, доступных для VBA, таких как регулятор размера шрифта, селектор шрифта и масштабирование. (Например, эмуляция селектора размера шрифта Word )


2

Краткое примечание по форматированию

Потому что StackExchange использует Markdown и Prettify.js к ответам на кодирование можно добавить языковой флаг, что обычно делает их более профессиональными. Хотя я не могу гарантировать, что это сделает вас лучше в гольфе в VBA, я могу гарантировать, что это сделает вас похожими на вас.

Добавление любого из флагов ниже изменит

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

в

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

Языковые теги VBA

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

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

Примечание: последний преобразует все сегменты кода в вашем ответе, в то время как предыдущий преобразует только непосредственно следующие сегменты кода


lang-vbа? - Странно, что это форматирует лучше, чем lang-vbaдля ответов VBA.
Greedo

1
@Greedo, потому что пока lang-vbaподсветка обеспечивает, она на самом деле просто подсветка по умолчанию. Очевидно, VBA на самом деле не был реализован в Prettify.js, поэтому нам придется придерживаться выделения VB
Тейлор Скотт

2

множественный If .. Then проверки

Как и в других языках, несколько Ifпроверок обычно можно объединить в одну строку, что позволяет использовать And/ Or(то есть &&/ ||в C и других), который в VBA заменяет и a, Thenи an End If.

Например, с вложенным условным выражением ( 93 символа):

'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

может стать ( 69 символов):

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

Это также работает с не вложенными условными выражениями.

Рассмотрим ( 84 символа):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Это может стать ( 51 символ):

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

1
в операторах If - then часть «End - if» является необязательной, если вы пишете код в одну строку.
Stupid_Intern

@newguy Правильно. Смотрите также этот другой ответ: codegolf.stackexchange.com/a/5788/3862
Гаффи

Вышеупомянутое утверждение может быть сокращено далее доd=iif(a=b or c=b,0,d)
Тейлор Скотт

2

Конечные Forпетли

При использовании ForпетельNext строка не нуждается в имени переменной (хотя, вероятно, ее лучше использовать в обычном кодировании).

Следовательно,

For Variable = 1 to 100
    'Do stuff
Next Variable

можно сократить до:

For Variable = 1 to 100
    'Do stuff
Next

(Экономия зависит от имени вашей переменной, хотя, если вы играете в гольф, это, вероятно, всего 1 символ + 1 пробел.)


1
2 символа, не забывайте считать пространство!
11684

Я почти никогда не идентифицирую переменную, даже в обычном коде!
dnep

2

Разбить строку на массив символов

Иногда бывает полезно разбить строку на отдельные символы, но может потребоваться немного кода, чтобы сделать это вручную в 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

Вместо этого вы можете использовать одну строку, относительно минимальную цепочку функций, чтобы выполнить работу:

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

Это назначит вашу строку sв Variantмассивa . Однако будьте осторожны, так как последний элемент в массиве будет пустой строкой ( ""), которая должна быть обработана соответствующим образом.

Вот как это работает: StrConv функция конвертирует Stringв другой указанный вами формат. В этом случае 64 = vbUnicode, поэтому он преобразуется в формат Unicode. При работе с простыми строками ASCII результатом является нулевой символ (не пустая строка ""), вставленный после каждого символа.

Следующее Split затем преобразует полученный результат Stringв массив, используя нулевой символ Chr(0)в качестве разделителя.

Важно отметить, что Chr(0)это не то же самое, что пустая строка "", и использование Spliton ""не вернет ожидаемый массив. То же самое относится и к vbNullString(но если вы играете в гольф, то зачем вам вообще использовать такую ​​многословную константу?).


Следует отметить, что в конце массива есть дополнительная пустая строка в конце.
Говард

@ Говард Да, я должен. Это было в моей голове, пока я печатал это, должно быть, я заболел.
Гаффи

2

Использование With(Иногда! Смотрите сноску)

Использование этого Withоператора может значительно уменьшить размер кода, если вы несколько раз используете некоторые объекты.

то есть это ( 80 символов):

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

может быть закодировано как ( 79 символов):

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

Выше даже не лучший сценарий. При использовании чего-либо с Application, например, Excel.Applicationиз Access, улучшение будет гораздо более значительным.


* В зависимости от ситуации, Withможет быть или не быть более эффективным, чем это ( 64 символа):

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

2

Бесконечные циклы

Рассмотреть вопрос о замене

Do While a<b
'...
Loop

или

Do Until a=b
'...
Loop

с устаревшим, но меньшим количеством байтов

While a<b
'...
Wend

Если вам нужно выйти Subили Functionпреждевременно, то вместоExit ...

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

рассмотреть возможность End

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

Обратите внимание, что Endостанавливает выполнение всего кода и очищает любые глобальные переменные, поэтому используйте с умом


Вы должны рассмотреть возможность переписать последний раздел ( Forи End), чтобы отразить, что случай 100никогда не будет удовлетворен, и добавить ненужный байт
Тейлор Скотт,

Кроме того, хотя это очень разборчиво, вы можете рассмотреть возможность удаления пробелов, чтобы лучше продемонстрировать возможные преимущества этих методов (всегда полезно злоупотреблять автоформатированием в VBA для анализа кода)
Тейлор Скотт,

2

Используйте Spc(n)более Space(n),[Rept(" ",n)] илиString(n," ")

При попытке вставить несколько пробелов длины nиспользуйте

Spc(n)              ''  6  bytes

над

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

Примечание: я не уверен, почему, но кажется, что вы не можете присвоить выходные данные Spc(n)переменной, и что она должна быть напечатана напрямую - так что в некоторых случаях Space(n)это все же лучший путь.


2

Уменьшить Debug.Printи Printзвонки

Debug.Print [some value] 

(12 байт; обратите внимание на завершающий пробел) можно уменьшить до

Debug.?[some value]

(7 байт; обратите внимание на отсутствие пробела).

Так же,

Print 

(6 байт) может быть уменьшено до

?

(1 байт).

Кроме того, при работе в контексте анонимной функции непосредственного окна VBE Debugоператор может быть полностью отброшен, и вместо этого можно считать, что печать в непосредственное окно VBE через ?STDIN / STDOUT

Специальные символы

При печати строк вы также можете использовать специальные символы вместо &. Они позволяют использовать альтернативные форматы в том, что печатается, или в пробелах

Для объединения переменных строк, а не

Debug.Print s1 &s2

Вы можете использовать точку с запятой ;

Debug.?s1;s2

Эта точка с запятой является поведением по умолчанию для последовательных строк, если нет двусмысленности. Так что они действительны:

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

Но нет

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

Обратите внимание, что а; в конце строки подавляет новую строку, так как новые строки по умолчанию добавляются после каждой печати. Подсчет байтов, возвращаемых кодом VBA, обсуждается

Для объединения с вкладкой используйте запятую ,(фактически 14 пробелов, но в соответствии с)

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

Наконец, вы можете использовать объявления типов для объединения строк вместо;, каждое из которых имеет свое небольшое влияние на форматирование. Для всего ниже a = 3.14159приведена первая строка

Debug.?a&"is pi" -> " 3 is pi" 'dims a as long, adds leading and trailing space to a
Debug.?a!"is pi" -> " 3.14159 is pi" 'dims a as single, adds leading and trailing space
Debug.?a$"is pi" -> "3.14159is pi" 'dims a as string, no spaces added

2

Используйте помощника, SubчтобыPrint

Если код требует использования более шести Debug.? операторов, вы можете уменьшить байты, заменив все Debug. линии с вызовом Sub, как показано ниже. Чтобы напечатать пустую строку, вам нужно позвонить, p ""так как параметр требуется.

Sub p(m)
Debug.?m
End Sub

1
Для того, чтобы напечатать новую строку с этим вы только должны были бы p""или , если это может быть несогласованным, p". Однако в подавляющем большинстве случаев, когда это применимо, имеет смысл использовать строковую переменную и печатать строковую переменную только в конце.
Тейлор Скотт

1

Используйте Array() Choose()вместо SelectилиIf...Then

При назначении переменной на основе значения другой переменной имеет смысл выписать шаги с If...Thenпроверками, например так:

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

Тем не менее, это может занять много места в коде, если нужно проверить более одной или двух переменных (в любом случае, как правило, есть и лучшие способы сделать это).

Вместо этого Select Caseоператор помогает уменьшить размер проверок, заключая все в один блок, например:

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

Это может привести к гораздо меньшему коду, но для очень простых случаев, таких как этот, есть еще более эффективный метод: Choose()эта функция выберет значение из списка на основе значения, переданного ему.

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

Опция select ( aв данном случае) - это целочисленное значение, переданное в качестве первого аргумента. Все последующие аргументы являются значениями на выбор (с 1 индексом, как и большинство VBA). Значения могут быть любого типа данных, если они соответствуют устанавливаемой переменной (т.е. объекты не работают безSet ключевого слова) и даже могут быть выражениями или функциями.

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

Дополнительная опция - использовать Arrayфункцию для получения того же эффекта при сохранении другого символа:

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

Интересное и, возможно, очень полезное использование для игры в гольф состоит в том, чтобы использовать это в сочетании с тем IIf()или иным 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

Смещенные в бит значения RGB

Благодаря тому, что Excel обрабатывает цвета (шестнадцатеричное шестнадцатеричное целое число без знака), вы можете использовать целые числа с отрицательными знаками, из которых Excel будет использовать только правильные 6 байтов для назначения значения цвета.

Это немного сбивает с толку, поэтому некоторые примеры приведены ниже

Допустим, вы хотите использовать белый цвет, который хранится как

rgbWhite

и эквивалентно

&HFFFFFF ''#value: 16777215

чтобы упростить эту задачу, все, что нам нужно сделать, - это найти отрицательное шестнадцатеричное значение, оканчивающееся на, FFFFFFи, поскольку отрицательные шестнадцатеричные значения в должны быть в формате FFFFXXXXXX(такой, который Xявляется действительным шестнадцатеричным), начиная с FFFFFFFFFF( -1) до FFFF000001(-16777215 )

Зная это, мы можем обобщить, что формула

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

Используя это, некоторые полезные преобразования

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

Приятно знать, что там происходит, я просто случайно обнаружил в этом вопросе - но это четкое объяснение показывает, как именно это работает. Еще одна вещь, которую нужно иметь в виду, заключается в том, что некоторые ключевые цвета можно уменьшить с помощью математических операторов; rgbWhite= 2^24-1хотя, возможно, еще больше уменьшится, если вы пропустите -1, чтобы приблизиться
Greedo

1
Фактически, вот список цветов с их математическими представлениями, которые короче положительных или отрицательных десятичных версий: &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 не обязательно завершен, но я думаю, что проделал довольно основательную работу
Greedo

1

Пропустить терминал "при печати в Immediate Window

Учитывая функцию ниже, которая должна использоваться в окне отладки

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

Терминал "может быть отброшен на -1 байт, оставив строку незамкнутой, и программа должна выполнить то же самое, без ошибок

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

Еще более удивительным является то, что это может быть сделано в рамках полностью определенных подпрограмм.

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

Вышеуказанная подпрограмма работает так, как ожидалось, и автоматически форматирует

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

1

Используйте переменные Truthy и Falsey в условных выражениях

Иногда называется неявное преобразование типа - непосредственно используя тип номера в If, [IF(...)]илиIIf(...) заявление, с помощью truthy и falsey характер этого номера может абсолютно спасти вас несколько байтов.

В VBA любая переменная числового типа, отличная от нуля, считается истинной (и, следовательно, ноль 0, является единственным значением Falsey) и, таким образом,

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

может быть сжат до

If B Then C=B Else C=D

и дальше

C=IIf(B,B,D)

1

Адресные листы по имени

Вместо адресации WorkSheetобъекта путем вызова

Application.ActiveSheet
''  Or 
ActiveSheet   

Можно использовать

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

Или, более предпочтительно, можно получить доступ к объекту напрямую и использовать

Sheet1

1

Возведение в степень и LongLongs в 64-битном VBA

Общая форма возведения в степень,

A to the power of B

Может быть представлен как в VBA как

A^B 

Но только в 32-разрядных установках Office , в 64 -разрядных установках Office, самый короткий путь, который вы можете представить без ошибок, это

A ^B

Это связано с тем, что в 64-битных версиях VBA ^служит литералом возведения в степень и LongLongсимволом объявления типа . Это означает, что может возникнуть некоторый довольно странный, но правильный синтаксис, такой как

a^=2^^63^-1^

который назначает переменную aдля хранения максимального значенияLonglong


1

Сжать байтовые массивы как строку

Для вызовов, которые требуют, чтобы решение содержало постоянные данные, может быть полезно сжать эти данные в одну строку, а затем выполнить итерацию по строке для извлечения данных.

В VBA любое значение байта может быть напрямую преобразовано в символ с

Chr(byteVal)

И значение longили integerможет быть преобразовано в два символа с

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

Так что для byteмассива алгоритм сжатия будет выглядеть примерно так:

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$

Отметим, что Select Caseраздел реализован из-за символов, которые не могут быть сохранены как литералы в строке.

Из полученной строки, которая будет выглядеть примерно так

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

Данные затем могут быть извлечены с помощью Ascи Midфункции, например ,

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

1

Используйте неправильные константы

В некоторых случаях VBA позволяет использовать не выраженные в списке или неправильные константы в выражениях, которые требуют постоянных значений. Они часто являются устаревшими значениями и короче по длине, чем правильные значения.

Например, приведенные ниже значения могут быть использованы, когда rng.HorizantalAlignmentсвойство удерживает значение .

неподходящийправильныйГенеральная КонстантаxlHAlign  постоянная11xlGeneralxlHAlignGeneral2-4131xlLeftxlHAlignLeft3-4108xlCenterxlHAlignCenter4-4152xlRightxlHAlignRight55xlFillxlHAlignFill6-4130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection8-4117xlDistributedxlHAlignDistributed

Это означает, например, что установка ячейки в центре текста с

rng.HorizantalAlignment=-4108

может быть сокращено до

rng.HorizantalAlignment=3

заменив неподходящее постоянное значение 3на правильное значение -4108. Обратите внимание, что если вы получите rng.HorizantalAlignmentзначение свойства, оно вернет правильное значение. В этом случае это будет -4108.


1

В Excel создайте числовые массивы с помощью принудительного выбора диапазонов

Когда постоянный одномерный набор чисел смешанной длины, Sнеобходимо, будет более эффективно использовать [{...}]нотацию для объявления диапазона и затем приводить его к числовому массиву, а не использовать Split(String)нотацию или подобное.

Используя этот метод, изменение Δколичество байтовзнак равно-5 байтов начисляется за все S,

пример

Например,

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

может быть написано как

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

Кроме того, стоит отметить, что, хотя этот метод не допускает прямого индексирования, он допускает итерацию по циклу for напрямую, т.е.

For Each s In[{1,3,5,7,9,2,4,6,8}]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.