VBA'da golf için ipuçları


16

Benzer bu , bu ve bu soru ...

Golf yapmak için hangi genel ipuçlarınız var VBA? Ben genel olarak en azından biraz VBA(örneğin "yorumları kaldırmak" bir cevap değildir) belirli olan golf sorunları kod uygulanabilir uygulanabilir fikirler arıyorum . Lütfen cevap başına bir ipucu gönderin.

Diğer dillerle çalışırken en güçlüyüm VBAve VBAbu sitede çok fazla golfçü görmüyorum .


Politikaya göre Topluluk Wiki'sine dönüştürülür.
dmckee --- eski moderatör yavru kedi

Üzgünüm, bu benim için otomatik değildi!
Mart'ta Gaffi

Sorunsuz. Aslında, CW'yi kullanıcılardan uzağa sorma gücünü aldılar (bence hala cevaplar alabilirsiniz). Moderatörlerin dikkatini çekmek için işaretleyebilirsiniz, ancak CodeGolf'un aldığı kadar az aktivite buna gerek yoktur.
dmckee --- eski moderatör yavru kedi

2
VBA, birkaç sözdizimi kısayoluyla nispeten ayrıntılı bir dildir. En iyi puanı alacaksanız, VBA iyi bir seçim olmayabilir. Eğer yeteneklerinizi geliştirmek istiyorsanız, size daha fazla güç.
Bay Llama

2
@GigaWatt Benim becerilerimi geliştirmek. Aslında farklı zorluklarla oynadığımdan beri, VBA ile çalışmak için birkaç yeni numara seçtim! VBA ile gerçek bir kod golfü mücadelesi kazanmayı beklemiyorum , ama iyi bir uygulama. :-)
Gaffi

Yanıtlar:


8

Exploit ByRefsubs çağrılırken varsayılan

Birkaç ek karakter kaydetmek için a Subyerine bir çağrı kullanmak bazen mümkündür Function...

Bu ( 87 karakter)

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

yeniden çalışılabilir ( 73 karakter):

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

Bu, sonsuza kadar döngü ETMEYECEK , ancak bdeğerini asla yeniden atamadığınız görünse de .

Yukarıda belirtilenler bir Functionçağrı kullanmaz , bunun yerine çağrının ByRef("Referans ile") işlevinden yararlanır Sub. Bunun anlamı geçilen argümanın çağıran fonksiyondaki ile aynı değişkendir ( ByValbir kopya olan "Değere Göre" geçmenin aksine ). Geçirilen değişkente yapılan herhangi bir değişiklik geri çağırma işlevine çevrilir.

Varsayılan olarak, tüm bağımsız değişkenleri olarak alır ByRef, bu yüzden bunu tanımlamak için karakterleri kullanmaya gerek yoktur.

Yukarıdaki örnek, işlevinizin dönüş değerine bağlı olarak sizin için mükemmel bir şekilde tercüme edilmeyebilir. (yani iletilenden farklı bir veri türü döndürmek), ancak bu aynı zamanda orijinal değişkeninizi değiştirirken bir dönüş değeri elde etme olasılığına da izin verir.

Örneğin:

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

Anlık Pencerede VBA kodunu yazın ve çalıştırın

Anlık Pencere geçerli herhangi bir VBA yürütülebilir deyimini değerlendirir. Hemen Pencereye kod düzenleyicide yaptığınız gibi bir ifade girin. VBA kodunu hızlı bir şekilde yürütür ve birçok ek karakter kaydedebilir, çünkü:

  1. Soru işaretini (?) İfadenin başına koymak, Anlık Pencereye kodunuzun sonucunu görüntülemesini söyler.

enter image description here

  1. Kodunuzda bir Sub ve End Sub kullanmanıza gerek yoktur.

enter image description here


PPCG'nin gönderisine tag ile cevap vermek için Anlık Pencerede VBA kodu örneği : A olmadan A Harfi

?Chr(88-23);

cevapladı Joffan .


Kredi resimleri: Excel Campus


1
Yine de bir REPL ortamı kullanıyor? Bu, bir program veya işlev değil, sadece bir pasaj olduğu anlamına gelir
caird coinheringaahing

Ben eklemek için başka bir örnek de satır içi değişkenler oluşturmak olabilir düşünüyorum; örneğin a="value":?aönce değerini ayarlar a, sonra yazdırır.
Greedo

6

Döngüden Önce Koşullu Kontroller

Döngülerle birlikte kullanıldığında bazı koşullu denetimler gereksizdir. Örneğin For, başlatma koşulu çalışma koşulunun kapsamı dışındaysa bir döngü işlenmez.

Başka bir deyişle, bu ( 49 karakter):

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

Buna dönüştürülebilir ( 24 karakter):

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

Alttaki yorum yanlış. B = 0 ise, döngü girilecektir. pastebin.com/97MBB7hq
QHarr

5

Değişken Beyanı

VBA'daki çoğu durumda, dışarıda bırakabilirsiniz Option Explicit(genellikle varsayılan olarak atlanır) ve Dimdeğişkenlerinizin çoğunu atlayabilirsiniz .

Bunu yaparken, ( 96 Karakter):

Option Explicit

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

Bu olur ( 46 karakter):

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

Belirli nesneleri (örneğin, diziler) kullanmanız gerekiyorsa, yine de Dimbu değişkene ihtiyacınız olabilir .


Bir saniye, sorunuza kendi cevabınızı kabul ettiniz. Hoş değil dostum.
Taylor Scott

1
@TaylorScott Bu bir wiki yazısı - puan yok ve bu durumda en iyi tek bir cevap yok. :) Soru listemde bayrak bulundurmamak için ~ 5 yıl önce cevabı kabul ediyorum.
Gaffi

1
@TaylorScott ayrıca kendi cevabınızı kabul ederseniz +15 veya +2 ​​(kabul etmek için)
almazsınız

5

Evaluate() Ve []

Daha önce belirtildiği gibi, sabit kodlu aralık çağrıları köşeli parantez [A1]gösterimi kullanılarak azaltılabilir . Ancak bundan çok daha fazla faydası vardır.

MSDN belgelerine göre , Application.Evaluate()yöntem Name, Microsoft Excel'in adlandırma kuralında tanımlandığı gibi tek bir bağımsız değişken alır .

NB [string]kısaltmasıdır Evaluate("string")( ""dize veri tipini gösteren konuşma işaretlerine dikkat edin ), ancak sonunda kapsanan birkaç önemli fark vardır.

Peki bunların hepsi kullanım açısından ne anlama geliyor?

Temel olarak, [some cell formula here]bir excel çalışma sayfasındaki bir hücreyi temsil eder ve içine hemen hemen her şeyi koyabilir ve normal bir hücre ile yapabileceğiniz her şeyi alabilirsiniz

Ne içeri giriyor

Özetle, örneklerle

  • A1 tarzı referanslar. Tüm referanslar mutlak referanslar olarak kabul edilir.
    • [B7] o hücreye bir başvuru döndürür
    • Referanslar mutlak olduğundan, ?[B7].Addressgeri dönüşler"B$7$"
  • Aralıklar Aralıklarla, kesişen nokta ve birleşim işleçlerini (sırasıyla iki nokta üst üste, boşluk ve virgül) referanslarla kullanabilirsiniz.
    • [A1:B5]A1:B5(Aralık) değerine aralık referansı döndürür
    • [A1:B5 A3:D7]A3:B5(Kesişim) öğesine bir aralık referansı döndürür
    • [A1:B5,C1:D5]A1:D5(teknik olarak A1:B5,C1:D5) (Birlik) aralığına referans verir
  • Tanımlı isimler
    • [myRange]A1: G5'e atıfta bulunmak gibi kullanıcı tanımlı
    • Otomatik, tablo adları gibi [Table1](muhtemelen codegolf için daha az yararlıdır)
    • [Formulas]> [Name Manager]Menüsünde bulabileceğiniz her şey
  • Formüller
    • Çok faydalı ; bir hücreye girebilecek herhangi bir formül içeri girebilir Evaluate()veya[]
    • [SUM(1,A1:B5,myRange)]Burada myRange aralığındaki değerlerin aritmetik toplamını döndürür , VBA değişkeni değil bir çalışma kitabının adını belirtir
    • [IF(A1=1,"true","false")](Vba eşdeğerinden 1 bayt daha kısa Iif([A1]=1,"true","false"))
    • Dizi formülleri [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]- uzunluğu 2'den büyük olan aralıktaki tüm dizeleri boşlukla birleştirir
  • Harici referanslar
    • !Bir hücreye veya başka bir çalışma kitabında tanımlanan bir ada başvurmak için işleci kullanabilirsiniz
    • [[BOOK1]Sheet1!A1]Book1 veya A1 bir aralık başvurusu döner ['[MY WORKBOOK.XLSM]Sheet1!'A1]aynı girişi içinMY WORKBOOK
    • Not '(adlarında boşluk ve varsayılan adlı çalışma kitapları için uzatma eksikliği çalışma kitapları için BOOK+n)
  • Grafik Nesneleri (MSDN makalesine bakın)

NB Öyle bir göz atın, bu bilgi için SO üzerinde aşırı bir soru sordu orada daha iyi bir açıklama için

Ne çıkıyor

İçeri girene benzer şekilde, ortaya çıkan şey bir çalışma sayfası hücresinin döndürebileceği her şeyi içerir. Bunlar standart Excel veri türleridir (ve VBA eşdeğerleri):

  • Mantıksal ( Boolean)
  • Metin ( String)
  • Sayısal ( Double)
  • Error ( Variant/Error) (bunlar bozulmayan hatalardır, yani kod yürütülmesini durdurmaz, ?[1/0]iyi çalışır)

Ancak, hücrelerin yapamayacağı birkaç şey geri döndürülebilir:

  • Aralık referansı ( Range) (yukarıdaki bölümlere bakın)
  • Diziler ( Variant())

Diziler

Gösterildiği gibi, []standart Excel veri türlerinden birini döndüren dizi formüllerini değerlendirmek için kullanılabilir; örneğin [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]geri döner Text. Ancak tür Evaluatedizileri de döndürebilir Variant. Bunlar olabilir

kodlanmış:

[{1,2;3,4}]- bir 2D dizi çıkarır: ,sütun ayırıcıdır, ;satırları ayırır. 1D dizisi çıktısı alabilir

Dizi Formülleri:

[ROW(A1:A5)]- bir 2D dizi çıkarır {1,2,3,4,5}, yani (2,1) ikinci öğedir (yine de bazı işlevler 1D dizileri çıkarır)

  • Hangi nedenle olursa olsun, bazı işlevler varsayılan olarak diziler döndürmez

[LEN(A1:A5)] yalnızca aralığın 1. hücresindeki metnin Uzunluğunu çıktılar

  • Ancak bunlar diziler vermek için zorlanabilir

Split([CONCAT(" "&LEN(A1:A5))]) ilk öğenin boş olduğu 0 ila 5 arası bir 1D dizisi verir

[INDEX(LEN(A1:A5),)]başka bir geçici çözümdür, temel olarak, istenen dizi döndürme davranışını elde RAND()etmek için, çalışma sayfası formüllerinizi geçici hale getirmek için anlamsız bir şekilde eklemeye benzer bir dizi işleme işlevi kullanmanız gerekir .

  • Bu konuda daha iyi bilgi almak için SO hakkında bir soru sordum lütfen onları bulmak / daha iyi seçeneklerle yorum

Evaluate() vs []

Farkında olmak Evaluate()ve []farkında olmak için birkaç fark vardır

  1. Dizeler ve sabit kodlanmış
    • Belki de en önemli fark olan Evaluate, [] sabit kodlu bir girdi gerektirdiği bir dize girdisi alır
    • Bunun anlamı, örneğin değişkenlerle dize birikebilir kodunuzu Evaluate("SUM(B1,1,"&v &",2)")tanımlıyorsunuz [B1], 1, 2ve değişkenv
  2. Diziler

    Bir Dizi döndürürken, bir dizi diziniyle yalnızca Değerlendir, kullanılabilir.

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

    eşittir

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

Mamut yazı için özür dilerim, eğer herkes alanları daha özlü hale getirebilir / eklemek için ipuçlarınız varsa, çekinmeyin. Ayrıca, bunlardan bazılarını araştırmama rağmen, VBA'da deney yaparak adil bir bölüm bulundu, bu yüzden eksik bir şey olduğunu hissetme hatalarını fark ederseniz, yorum yapmaktan / düzenlemekten çekinmeyin!
Greedo

1
Aslında dizilerin son bölümü biraz kapalı - hemen pencerede kullanılabiliri=[ROW(A1:A5)]:v=i(2,1):?v
Taylor Scott

@TaylorScott Böylece, daha önce tanımlanmamış değişkenlerde değerleri ayarlayabileceğiniz / tutabileceğinizden tamamen habersizdim, ancak bunun nedeni, Hemen Pencere 1 gömleklerini kavramaya başladığım için sanırım. Buna göre güncelledi
Greedo

Bu Match ile çalışır mı? Denedim, ama her zaman hata döndürür. Yine de bir dizi yerine bir dizi geçiyordu.
seadoggie01

5

birleştirin Nextİfadeleri

Next:Next:Next

Yoğunlaştırılabilir

Next k,j,i

için yineleyiciler nerede Fordöngüler vardır i, jve k- bu sırayla.

Örneğin aşağıdaki (69 Bayt)

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

65 bayta kadar yoğunlaştırılabilir

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

Ve bunun biçimlendirme ve girintiyi nasıl etkilediği kadarıyla, bunu ele almak için en iyi yaklaşımın bir sonraki ifadeyi ifade için en dışa hizalamak olduğunu düşünüyorum. Örneğin.

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

4

Ifİfadeleri Azaltma

Koşullu bir If ... Then ... Elsedenetim kullanarak bir değişken atarken End If, tüm denetimi tek bir satıra koyarak ortadan kaldırarak kullanılan kod miktarını azaltabilirsiniz .

Örneğin, bu ( 37 karakter):

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

Buna indirgenebilir ( 30 karakter)

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

Birden fazla iç içe koşullu koşulunuz varsa, bunları da bu şekilde en aza indirebilirsiniz:

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

Not :Bir içinde birden fazla satır / komut eklemek için izin verir Ifblokta.

Bunun gibi basit durumlarda, genellikle Elsedeğişkeni denetimden önce ayarlayarak If( 25 karakter) de kaldırabilirsiniz :

c = a
If a < b Then c = b

Daha da iyisi, yukarıdaki IIf()fonksiyon ( 20 karakter) kullanılarak buna daha da azaltılabilir :

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

3

Range("A1")Çağrıları Azalt ve Beğen

Range("A1").Value(17 Bayt) ve daha basit Range("A1")(11 Bayt) [A1](4 Bayt) değerine düşürülebilir


2
Veya genel olarak, VBA'da []değiştirmek Evaluate()için sadece aralıklı aramalardan çok daha çok yönlüdür. Örneğin WorksheetFunction.FuncName(args), sadece [FuncName(args)]gibi ?[SUMPRODUCT({1,3,5},{2,7,-1})]veya çok kullanışlı ile değiştirmek için kullanabilirsiniz [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Greedo, bilmediğim inanılmaz derecede önemli bir işlevsellik, bunu kendi cevabı olarak eklemelisin.
Taylor Scott

1
Elbette, kısa süre içinde bir şeyler yazacağım. Evet Evaluate("str")veya steno [str]VBA'da çok güçlü, sadece yakın zamanda öğrendim ve sanırım golf için de yararlı olacak!
Greedo

Çok yararlı, yeterli, bu yüzden cevaplarımı herhangi bir nedenle düşürüp düşüremeyeceğimizi görmek için geri dönüyorum
Taylor Scott

3

Boşlukları Kaldır

VBA, gerçekten ihtiyaç duymadığı birçok boşluk eklemek için otomatik olarak biçimlendirir. Metada , otomatik biçimlendirme ile eklenen baytları neden indirebileceğimize çok anlamlı gelen bir yanıt var . Yine de çok fazla kaldırmadığınızı doğrulamak önemlidir. Bir örnek olarak, sadece boşlukları kaldırarak neredeyse% 22 azaltılmış bir cevabım :

Orijinal sürüm: (188 bayt)

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

İndirimli sürüm: (146 bayt)

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

İndirgenmiş sürümü VBA'ya kopyalarsanız / yapıştırırsanız, otomatik olarak orijinaline genişler. Boşlukları kaldırmanın geçerli olduğu yerde oynayabilirsiniz. Şimdiye kadar bulduğumlar, VBA'nın belirli bir komutun görünmesi beklenen paterni takip ediyor gibi görünüyor, çünkü onsuz geçerli bir kod değil. İşte şimdiye kadar bulduğum bazıları:

  • Herhangi bir matematiksel işlemden önce ve sonra: +-=/*^vb.
  • Önce Tove Stepbir Foraçıklamada:For x=-3To 3Step 0.05
  • Aslında, herhangi ayrılmış kelimeden önceki ( To, &, Thenvs.) da bir sayı olarak bir değişmez böyle öncesinde eğer, ), ?, %, vb
  • Sonra &birleştirerek dizeleri:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • İşlev çağrılarından sonra: If s=StrReverse(s)Then
  • İşlev çağrıları içinde: Replace(Space(28)," ",0)

Otomatik biçimlendirme yoluyla boşluk olmayan karakterler eklendiğinde kural nedir? Gibi bir şey ?vs Printgördüğüm kabul edilebilir, ancak benzeri tip tanımlamada koyarak &değişken örneğin hemen sonra Debug.?a&"z"verir Debug.Print a&; "z". ;Bu hala izin verilir - çalıştırmak için kod eklendi karakter esastır?
Greedo

2
@Greedo Meta cevabın tarif ettiği şekilde görüyorum : Eğer editöre kopyalayıp yapıştırabiliyorsanız ve kod çalışacaksa sorun yok. IE, kodu yapıştırdığınızda VBA karakteri otomatik olarak geri eklerse sorun olmaz.
Mühendis Tost

1
Gerçekte Örneğin kapalı bir byte daha bırakabilirsiniz @EngineerToast: If i=1 Then hale gelebilir If i=1Then Genel bir kural değişmez aşağıdaki ayrılmış bir kelime gibi bir sayı, yani olması nedeniyle ), ?, %, .. vb a ayrılmalıdır gerekmez alanı
Taylor Scott

1
@EngineerToast, üçüncü mermi noktanızdan bir bayt bırakabilirsiniz, çünkü bir )(veya başka bir sayı olmayan değişmez değer) ve&
Taylor Scott

3

Pixel Art İçin Hazırlanın

Piksel sanat, Excel'in en güçlü alanlarından biridir, çünkü bir tuval inşa etmeye gerek yoktur, çünkü sizin için zaten oradadır - tek yapmanız gereken bazı küçük ayarlamalar yapmaktır

1) Hücreleri kare yapın

Cells.RowHeight=48

veya Alternatif olarak, 1 bayt daha fazla, ancak çalışmak çok daha kolay

Cells.ColumnWidth=2

2) Gerekli aralığı renklendirin

Herhangi bir Rangenesne çağrılarak renklendirilebilir

`MyRangeObj`.Interior.Color=`ColorValue`

Not: Bu, bu vikide belirtilen, []örneğin [A1:R5,D6]bir a Cells(r,c)veya Range(cellAddress)çağrı kullanımı sırasında gösterimin (örn. ) Kullanılmasıyla referans aralıkları gibi diğer hilelerle birleştirilebilir ve birleştirilmelidir . Ayrıca, bu wiki'de belirtildiği gibi, bu renk referanslarının boyutunu azaltmak için negatif renk değeri ile birleştirilebilir

Hızlı Referanslar

Aralık Referansı

Hücreye A1aşağıdaki yollardan herhangi biriyle başvurulabilir

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

ve Aralık A1:D4aşağıdaki yollardan biriyle referans gösterilebilir

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

Renk Referans

Black  0
White  -1
Red    255
Aqua   -256

3

Yerleşik işlevleri basitleştirin

Belirli işlevleri sık sık kullanırken, bunları kullanıcı tanımlı bir işleve yeniden atayın.

Aşağıdaki kod ( 127 karakter) aşağıdakilerden indirilebilir:

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 karakter):

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

Bunu ByRef hilesi ile birleştirerek daha da fazla karakter kaydedebilirsiniz ( 114'e kadar ):

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'yı tanımlamak için çok fazla karakter gerektirdiğinden bunu akıllıca yapın Function. İkinci kod bloğu aslında ilk daha büyük olurdu herhangi sayısı ne kadar az Format()aramalar.


2
sonuncusu, atama çağrısı gerekmez, yani a = f(w)azaltılabilirf w
Taylor Scott

3

STDIN ve STDOUT

Giriş değişkenleri ile Subrutin ve Functions girişleri

Public Sub A(ByRef B as String)

Aşağı indirilebilir

Sub a(b$) 

PublicveByRef çağrılar VBA ve dolayısıyla örtük için varsayılan vardır ve (neredeyse) her zaman bırakılabilir.

Tip edebi $kuvvetler btürden olmalı String.

Diğer tür değişmez değerleri

  • ! Tek
  • @ Para birimi
  • # Çift
  • % tamsayı
  • $ sicim
  • & Uzun
  • ^ LongLong (Sadece 64 Bit)

Ayrıca, giriş değişkenini varsayılan tür olarak Variantbırakabileceğiniz ve tür tabanlı hataları işlenmeyebileceğiniz genellikle kabul edilir . Örneğin. Sub E(F)hangi Ftipte olması beklenir Boolean[](rutin gibi geçirilecek E Array(True, False, False))

İçin Girilmesi Subrutinleri ve Acil Pencere Fonksiyonlar aracılığıylaCells

VBA'nın tamamen işlevsel bir konsolu yoktur ve bu nedenle herhangi bir resmi STDIN'i yoktur ve bu nedenle bazılarına geçen girdi ile .

Excel'de, genellikle bir hücreden veya hücre aralığından girdi alınması kabul edilir.

s=[A1]

örtük .valueolarak hücreden koyar [A1]( cells(1,1)veya olarak da adlandırılabilir)range("A1")

Örnek Sorun: Girişi bir mesaj kutusunda görüntüleme

Altyordam yoluyla Sub A:msgbox[A1]:End Sub

Anında Pencere İşlevi ile msgbox[A1]

Koşullu Derleme Bağımsız Değişkenleri İle Girme

VBA Projeleri, komut satırından veya VBAProject Özellikleri aracılığıyla argümanlar almayı destekler (proje gezgini aracılığıyla görüntüleme -> [VBA Projeniz] - (Sağ Tıklama) -> VBAProject Özellikleri -> Koşullu Derleme Bağımsız Değişkenleri)

Bu, büyük ölçüde Hata Kodu Sorunları

Koşullu Derleme Argümanı n=[some_value] verildiğinde, bu, değerine bağlı olarak bir hata kodu üretecek kodun yürütülmesine izin verir n. Not, bu n=, VBAProject Özellikler bölmesinin koşullu derleme bağımsız değişkenleri bölümünde kodunuza 2 bayt eklenmesini gerektirir .

Örnek Kod

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

İşlev Değeri Üzerinden Çıkış

Burada söylenecek çok şey yok, aşağıda belirtilen genel form, yapılabilecek kadar kompakttır.

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

NOT: vakaların büyük çoğunluğunda daha bayt yöntemini bir alt rutine dönüştürmek ve VBE anında penceresine çıktı (Aşağıya bakınız)

Gönderen çıktısı Subrutinleri ve FunctionVBE Immediates Pencere yoluyla s

VBE penceresine çıkış (VBE Hata Ayıklama Penceresi AKA), metin tabanlı zorluklar için VBA için yaygın bir çıkış yöntemidir, ancak Debug.Print "Text"çağrının büyük ölçüde golf oynayabileceğini hatırlamak önemlidir .

Debug.Print "Text"

işlevsel olarak aynıdır

Debug.?"Text"

olarak ?otomatik biçimler olarak Print.

Dan çıktısı SubDiğer yöntemleriyle rutinleri ve VBE Immediates Pencere fonksiyonları

Açık nadir durum sadece doğru olduğunda vesileyle, bu tür yazı tipi boyutu ayarlayıcı, yazı tipi seçicisi olarak VBA kullanılabilir daha önemsiz girdilerin bazı girdi almak ve yakınlaştırmak olabilir. (Ör. Word Yazı Tipi Boyutu Seçicisini Taklit Etme )


2

Biçimlendirme Hakkında Kısa Not

StackExchange Markdown ve Prettify.js kullandığından , kodlama yanıtlarınıza bir dil işareti eklemek mümkündür, bu da genellikle daha profesyonel görünmelerini sağlar. Bunun VBA'da golf oynamanızı daha iyi hale getireceğini garanti edemesem de, sizi olduğunuz gibi göstereceğini garanti edebilirim.

Aşağıdaki bayraklardan herhangi birini eklemek,

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

için

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

VBA Dil Etiketleri

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

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

Not: İkincisi cevabınızdaki tüm kod parçalarını dönüştürürken önceki kod sadece hemen takip eden kod parçalarını dönüştürür


lang-vbha? - Bu formatların lang-vbavba cevaplarından daha iyi formatları .
Greedo

1
@Greedo, çünkü lang-vbavurgulama sağlarken , aslında sadece varsayılan vurgulamadır. Görünüşe göre VBA aslında Prettify.js'de uygulanmadı, bu yüzden VB vurgulamasına sadık kalmalıyız
Taylor Scott

2

Birden fazla If .. Thenkontrol

Diğer dillerde olduğu gibi, çoklu Ifkontroller genellikle tek bir satırda birleştirilebilir ve VBA'da a ve an'ın yerini alan And/ Or(yani &&/ ||C ve diğerlerinde) kullanımına izin verir .ThenEnd If

Örneğin, iç içe koşullu ( 93 karakter):

'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

olabilir ( 69 karakter):

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

Bu, iç içe olmayan koşullarla da çalışır.

Düşünün ( 84 karakter):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Bu olabilir ( 51 karakter):

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

1
if - then deyiminde "End - if" bölümü isteğe bağlı ise kodu tek satıra yazmanızı sağlar.
Stupid_Intern

@newguy Doğru. Ayrıca bu diğer yanıta da bakınız: codegolf.stackexchange.com/a/5788/3862
Gaffi

Yukarıdaki açıklama daha da yoğunlaştırılabilird=iif(a=b or c=b,0,d)
Taylor Scott

2

Bitirme ForDöngüleri

ForDöngüler kullanırken ,Next satırın değişken bir adı olması gerekmez (normal kodlamada kullanmak daha iyidir).

Bu nedenle,

For Variable = 1 to 100
    'Do stuff
Next Variable

kısaltılabilir:

For Variable = 1 to 100
    'Do stuff
Next

(Tasarruflar değişken adınıza bağlıdır, ancak golf oynuyorsanız, bu muhtemelen sadece 1 karakter + 1 boşluktur.)


1
2 karakter, alanı saymayı unutmayın!
11684

Normal kodda bile, değişkeni neredeyse hiç tanımlayamıyorum!
dnep

2

Bir dizeyi karakter dizisine bölme

Bazen bir dizeyi tek tek karakterlere ayırmak yararlı olabilir, ancak VBA'da bunu manuel olarak yapmak biraz kod alabilir.

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

Bunun yerine, işi yapmak için tek bir satır, nispeten az sayıda işlev zinciri kullanabilirsiniz:

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

Bu dize atar siçin Variantdiziden a. Bununla birlikte, dizideki son öğe ""uygun şekilde işlenmesi gereken boş bir dize ( ) olacağından dikkatli olun .

Şöyle çalışır: StrConvİşlev a String, belirttiğiniz başka bir biçime dönüştürür . Bu durumda, 64 = vbUnicode, bu yüzden bir unicode biçimine dönüştürür. Basit ASCII dizeleriyle uğraşırken, sonuç ""her karakterden sonra boş bir karakter (boş bir dize değil ) eklenir.

Aşağıdakiler SplitsonuçtaString , null karakterini kullanarak bir diziyeChr(0) sınırlayıcı olarak .

Bu notu için önemlidir Chr(0)boş dize aynı değildir ""ve kullanma Splitile ilgili ""Tahmin edebileceğiniz dizi döndürmez. Aynı şey için de geçerlidir vbNullString(ancak golf oynuyorsanız, neden böyle bir ayrıntılı sabiti ilk etapta kullanasınız?).


Sonuçta elde edilen dizinin sonunda ek bir boş dize bulunduğunu belirtmelisiniz.
Howard

@ Evet, yapmalıyım. Bunu yazarken kafamdaydı, aklımdan çıkmış olmalı.
Gaffi

2

Kullanma With(Bazen! Dipnota bakın)

Kullanmak WithBazı nesneleri tekrar tekrar kullanırsanız ifadenin kullanılması kod boyutunuzu önemli ölçüde azaltabilir.

yani bu ( 80 karakter):

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

(şekilde kodlanabilir 79 karakter):

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

Yukarıdakiler en iyi senaryo bile değildir. Access içinden Applicationolduğu gibi bir şey kullanırsanız Excel.Application, iyileştirme çok daha önemli olacaktır.


* Duruma bağlı olarak Withbundan daha verimli olabilir veya olmayabilir ( 64 karakter):

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

2

Sonsuz Döngüler

Değiştirmeyi düşünebilirsiniz

Do While a<b
'...
Loop

veya

Do Until a=b
'...
Loop

antika ancak düşük bayt sayısı ile

While a<b
'...
Wend

Bir Subveya Functionerken çıkmanız gerekiyorsa , bunun yerineExit ...

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

düşünmek End

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

Not o Enddurur böylece akıllıca kullanan küresel değişkenler üzerinden tüm kod yürütme ve temizler,


Davanın asla karşılanmayacağını ve gereksiz bir bayt eklemesini yansıtmak için son bölümü ( Forve End) yeniden yazmayı düşünmelisiniz100
Taylor Scott

Ayrıca, bu çok okunaklı olsa da, bu yöntemlerin olası faydalarını daha iyi göstermek için boşlukları kaldırmayı düşünebilirsiniz (kodlama için VBA'daki otomatik biçimlendirmeyi kötüye kullanmak her zaman iyidir)
Taylor Scott

2

Kullanım Spc(n)üzerinde Space(n), [Rept(" ",n)]ya daString(n," ")

Birkaç uzunluk boşluğu eklemeye çalışırken n,

Spc(n)              ''  6  bytes

bitmiş

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

Not: Neden olduğundan emin değilim, ancak çıktısını atayamayacağınız anlaşılıyor Spc(n) bir değişkenin doğrudan yazdırılması gerektiği anlaşılıyor - bu nedenle bazı durumlarda Space(n)hala en iyi yol.


2

azaltmak Debug.Print vePrint aramalar

Debug.Print [some value] 

(12 bayt; arka boşluğa dikkat edin)

Debug.?[some value]

(7 Bayt; sondaki boşluk eksikliğine dikkat edin).

Benzer şekilde,

Print 

(6 Bayt),

?

(1 Bayt).

Ayrıca, anonim bir VBE anlık pencere işlevi bağlamında çalışırken, Debugifade tamamen bırakılabilir ve bunun yerine VBE anlık penceresine? STDIN / STDOUT olduğu varsayılabilir.

Özel karakterler

Dizeleri yazdırırken, bunun yerine özel karakterleri de kullanabilirsiniz. & . Bunlar, yazdırılan veya boşluk boşluğunun kaldırılmasında alternatif biçimlere izin verir

Değişken dizeleri birleştirmek yerine

Debug.Print s1 &s2

Noktalı virgül kullanabilirsiniz ;

Debug.?s1;s2

Bu noktalı virgül, belirsizlik olmadığı sürece ardışık dizeler için varsayılan davranıştır.

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

Ama değil

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

A; satırın sonunda yeni satırlar bastırılır, çünkü her satırdan sonra satır başı varsayılan olarak eklenir. VBA kodu tarafından döndürülen bayt sayımı tartışılıyor

Bir sekmeye katılmak için virgül kullanın ,(aslında 14 boşluk, ancak göre)

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

Son olarak, her biri biçimlendirme üzerinde kendi hafif etkisine sahip olmak yerine; dizeleri birleştirmek için tür bildirimlerini kullanabilirsiniz. Aşağıdakilerin a = 3.14159tümü için ilk satır

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

Bir yardımcı SubkullanınPrint

Kod altıdan fazla Debug.? deyim kullanılmasını gerektiriyorsa , tüm Debug'i değiştirerek baytları azaltabilirsiniz. aşağıdaki gibi bir Sub çağrısına sahip hatlar. Boş bir satır yazdırmak için p ""parametre gerektiğinden aramanız gerekir.

Sub p(m)
Debug.?m
End Sub

1
Sadece ihtiyacınız olan p""veya sonlandırılamayan bir satır yazdırmak için p". Bununla birlikte, bunun geçerli olabileceği vakaların büyük çoğunluğunda, bir dize değişkeni kullanmak ve yalnızca dize değişkenini sonunda yazdırmak daha mantıklıdır.
Taylor Scott

1

Yerine Array() Choose()kullanınSelectVeyaIf...Then

Bir değişkeni başka bir değişkenin değerine göre atarken, adımları If...Thenkontrollerle yazmak mantıklıdır , şöyle:

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

Ancak, kontrol edilecek bir veya iki değişkenten fazlası varsa, bu çok fazla kod alanı kaplayabilir (yine de bunu yapmanın hala daha iyi yolları vardır).

Bunun yerine, Select Caseifade , her şeyi bir blokta kapatarak çeklerin boyutunu azaltmaya yardımcı olur, örneğin:

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

Bu, çok daha küçük bir koda yol açabilir, ancak bunun gibi çok basit durumlar için, daha da verimli bir yöntem vardır: Choose()Bu işlev, kendisine verilen değere bağlı olarak bir listeden bir değer seçer.

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

Seçme seçeneği ( abu durumda) ilk argüman olarak iletilen bir tamsayı değeridir. Sonraki tüm bağımsız değişkenler seçilebilecek değerlerdir (çoğu VBA gibi 1 dizinli). Değerler, ayarlanan değişkenle eşleştiği sürece herhangi bir veri türü olabilir (yani nesneler Setanahtar kelime olmadan çalışmaz ) ve hatta ifadeler veya işlevler olabilir.

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

Ek bir seçenek, Arraybaşka bir karakteri kaydederken aynı efekti elde etmek için işlevi kullanmaktır :

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

Golf için ilginç ve muhtemelen çok yararlı bir kullanım, bunu bir IIf()veya başka biriyle birlikte kullanmaktır Choose():A1=IIf(a=Choose(b,c,d,e),Choose(Choose(f,g,h,i),j,k,l),Choose(IIf(m=n,Choose(p,q,r,s),IIf(t=u,v,w)),x,y,z))
Gaffi

1

Bit Kaydırmalı RGB Değerleri

Excel'in renkleri işleme biçimi nedeniyle (işaretsiz, 6 karakterli onaltılık tam sayı), excel bir renk değeri atamak için yalnızca sağ 6 baytı kullanacak olan negatif işaretli tamsayılardan yararlanabilirsiniz.

Bu biraz kafa karıştırıcıdır, bu nedenle aşağıda bazı örnekler verilmiştir

Diyelim ki saklanan beyaz rengi kullanmak istiyorsunuz

rgbWhite

ve eşittir

&HFFFFFF ''#value: 16777215

golf yapmamız gereken tüm aşağı bu bir bulmak negatif son bulan onaltılık değerini FFFFFFbiçiminde olmalıdır negatif Hex değerleri ve yana FFFFXXXXXX(böyle Xgeriye saymaya geçerli bir onaltılık olduğu) FFFFFFFFFF( -1kadar) FFFF000001( -16777215)

Bunu bilerek, formülün

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

Bunu kullanarak, bazı yararlı dönüşümler

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

Orada neler olduğunu bilmek güzel, bunu bu soruda yanlışlıkla keşfettim - ama bu açık açıklama tam olarak nasıl çalıştığını gösteriyor. Akılda tutulması gereken bir başka şey de, bazı temel renklerin matematiksel operatörlerle azaltılabileceğidir; rgbWhite= 2^24-1kabaca oraya gitmek için
-1'i

1
Aslında, pozitif veya negatif ondalık sürümlerden daha kısa olan matematiksel gösterimleri ile renklerin bir listesi: &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 ille de tam değil, ama oldukça kapsamlı bir iş yaptığımı düşünüyorum
Greedo

1

Terminali atla "Anlık Pencereye yazdırırken

Hata ayıklama penceresinde kullanılacak aşağıdaki işlev verildiğinde

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

Terminal "-1 Bayt için bırakılabilir, dizge kapatılmadan bırakılabilir ve program hatasız olarak aynı şekilde yürütülür

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

Bundan daha da şaşırtıcı olan, bunun tam olarak tanımlanmış alt rutinler içinde yapılabilmesidir.

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

Yukarıdaki altyordam beklendiği gibi çalışır ve

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

1

Koşullu olarak Doğruluk ve Falsey Değişkenlerini kullanma

Bazen örtük tür dönüşüm olarak adlandırılır - doğrudan bir If , [IF(...)]ya daIIf(...) deyimi, bu sayının can kesinlikle kurtaracağım bazı bayt truthy ve Falsey doğayı kullanarak.

VBA'da, sıfır olmayan herhangi bir sayı türü değişkeninin doğru olduğu kabul edilir (ve dolayısıyla sıfır, 0 tek değer falseyidir) ve böylece

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

yoğunlaştırılabilir

If B Then C=B Else C=D

ve dahası

C=IIf(B,B,D)

1

İsme Göre Adres Sayfaları

Bir WorkSheetnesneyi arayarak adreslemek yerine

Application.ActiveSheet
''  Or 
ActiveSheet   

Biri kullanabilir

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

Veya Daha tercihen bir kişi nesneye doğrudan erişebilir ve

Sheet1

1

LongLong64-Bit VBA'da üs alma ve s

Genel üs alma şekli,

A to the power of B

VBA'da olduğu gibi gösterilebilir

A^B 

Ancak Office'in yalnızca 32 bitlik yüklemelerinde, Office'in 64 bitlik yüklemelerinde, hatasız olarak temsil edebileceğiniz en kısa yol budur

A ^B

Bunun nedeni, VBA'nın 64 Bit sürümlerinde ^hem üstel okuma değişmezi hem de LongLongtür bildirimi karakteri olarak işlev görmesidir . Bu, bazı garip görünümlü ancak geçerli bir sözdiziminin ortaya çıkabileceği anlamına gelir.

a^=2^^63^-1^

bir değişkenin amaksimum değerini tutmak için değişken atarLonglong


1

Bayt Dizilerini Dize Olarak Sıkıştır

Çözeltinin sabit verileri tutmasını gerektiren zorluklar için, bu verileri tek bir dize olarak sıkıştırmak ve daha sonra verileri almak için dize boyunca yineleme yapmak yararlı olabilir.

VBA'da, herhangi bir bayt değeri doğrudan şu karaktere dönüştürülebilir:

Chr(byteVal)

Ve bir longveya integerdeğeri iki karakterle dönüştürülebilir.

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

Yani bir bytedizi için bir sıkıştırma algoritması

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$

Dizinde Select Casedeğişmez olarak depolanamayan karakterler nedeniyle bölümün uygulandığına dikkat edin .

Ortaya çıkan dizeden,

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

Daha sonra veriler, Ascve Midişlevleri kullanılarak, örn.

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

1

Uygunsuz Sabitleri Kullan

VBA, bazı durumlarda, sabit değerler gerektiren ifadelerde liste dışı veya uygunsuz sabitlerin kullanılmasına izin verir. Bunlar genellikle eski değerlerdir ve uzunlukları uygun değerlerden daha kısadır.

Örneğin, rng.HorizantalAlignmentmülk tarafından bir değerin tutulmasına izin verilirken aşağıdaki değerler kullanılabilir .

uygunsuzuygunGenel SabitxlHAlign  Sabit11xlGeneralxlHAlignGeneral2-4131xlLeftxlHAlignLeft3-4108xlCenterxlHAlignCenter4-4152xlRightxlHAlignRight55xlFillxlHAlignFill6-4130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection8-4117xlDistributedxlHAlignDistributed

Bu, örneğin bir hücrenin, metninin ortalanması

rng.HorizantalAlignment=-4108

kısaltılabilir

rng.HorizantalAlignment=3

uygun değer 3için uygun olmayan sabit değeri değiştirerek -4108. rng.HorizantalAlignmentÖzellik değerini alırsanız , uygun değeri döndüreceğini unutmayın. Bu durumda, bu olurdu -4108.


1

Excel'de Zorlama Aralıklarına Göre Sayısal Diziler Oluşturma

Karışık uzunlukta sabit tek boyutlu bir dizi küme olduğunda, Sgerektiğinde, [{...}]bir aralık bildirmek için notasyonu kullanmak ve daha sonra Split(String)notasyonu veya benzerini kullanmak yerine bunu sayısal bir diziye zorlamak daha verimli olacaktır .

Bu yöntemi kullanarak, Δbayt sayısı=-5 bayt herkese tahakkuk ettirilir S.

Misal

Örneğin,

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

olarak yazılabilir

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

Ayrıca, bu yöntem doğrudan endekslemeye izin vermese de, doğrudan for döngüsü üzerinden yinelemeye izin verdiğini, yani

For Each s In[{1,3,5,7,9,2,4,6,8}]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.