SAS makro değişkenlerini çözme


13

SAS programlama dili bugün hâlâ kullanılıyor bulunuyor 1966 aksak, arkaik dil partner geri döndü. Orijinal derleyici PL / I'de yazılmıştır ve aslında sözdiziminin çoğu PL / I'den türemiştir. SAS ayrıca PL / I dilinden türeyen bir önişlemci makro diline sahiptir . Bu zorlukta, SAS makro dilinin bazı basit öğelerini yorumlayacaksınız.

SAS makro dilinde, makro değişkenler %letanahtar sözcük kullanılarak tanımlanır ve günlüğe yazdırma ile yapılır %put. İfadeler noktalı virgülle biter. İşte bazı örnekler:

%let x = 5;
%let cool_beans =Cool beans;
%let what123=46.lel"{)-++;

Makro değişken adları büyük / küçük harfe duyarsızdır ve her zaman normal ifadeyle eşleşir /[a-z_][a-z0-9_]*/i. Bu zorluğun amaçları için şunları söyleyeceğiz:

  • Makro değişkenleri yalnızca yazdırılabilir ASCII karakter tamamen oluşan değer tutabilen hariç ; , &ve%
  • Değerlerde ön veya arka boşluk olmayacak
  • Değerler asla 255 karakterden uzun olmayacaktır
  • Değerler boş olabilir
  • Değerlerdeki köşeli ayraçlar ve tırnak işaretleri eşleşmeyebilir
  • Orada önce ve sonra boşluk herhangi bir miktar olabilir =yılında %letaçıklamada ve bu boşluk göz ardı edilmelidir
  • Orada terminalin önce uzayın herhangi bir miktar olabilir ;yılında %letaçıklamada ve bu boşluk benzer şekilde göz ardı edilmelidir

Bir makro değişkeni çağrıldığında, değerine "çözümlendiğini" söyleriz. Makro değişkenleri, önceden bekletilerek çözülür &. Tanımlayıcının sonunu gösteren isteğe bağlı bir iz .vardır. Örneğin,

%put The value of x is &X..;

The value of x is 5.günlüğe yazar . İki periyodun gerekli olduğunu unutmayın, çünkü tek bir dönem tarafından tüketilecek &X.ve çözülecektir 5. Ayrıca tanımlanmış olsa da unutmayın xküçük harflerle, &Xaynı &xmakro değişken isimleri küçük harfe duyarlı değildir çünkü.

İşte burada zorlaşıyor. &Değişkenleri çözmek için birden fazla s birbirine eklenebilir &ve aynı seviyedeki yuvalama çözünürlüğündeki s aynı anda çözülebilir. Örneğin,

%let i = 1;
%let coolbeans1 = broseph;
%let broseph = 5;

%put &&coolbeans&i;  /* Prints broseph */
%put &&&coolbeans&i; /* Prints 5 */

Önce en içteki &çözülür ve çözünürlük dışa doğru devam eder. Değişken ad eşleştirmesi iştahla yapılır. İkinci %putifadede, işlemci aşağıdaki adımları gerçekleştirir:

  1. &ikarar verir 1ve en içteki lider &tüketilir,&&coolbeans1
  2. &coolbeans1karar verir broseph, bize verir&broseph
  3. &brosephkarar verir 5.

İzleyen .s .varsa, birden fazla &s olsa bile , yalnızca tek bir özünürlükte tüketilir .

Görev

Yeni %letsatırlarla ayrılmış tek bir %putdeyim ile tek bir deyim arasında 1 ile 10 arasında ifade verildiğinde , %putdeyimin sonucunu yazdırın veya döndürün . Giriş herhangi bir standart şekilde kabul edilebilir.

%letGirdinin her zaman geçerli olacağını ve ifadelerin ifadeden önce geleceğini varsayabilirsiniz %put. Tanımlanan değişkenler sonraki %letifadelerde yeniden tanımlanmayacaktır .

SAS'da gerçekten çalıştırılırsa, var olmayan değişkenleri çözen değişkenlerle ilgili herhangi bir sorun olmaz ve her şey yukarıda açıklandığı gibi sözdizimsel olarak doğru olacaktır.

Örnekler

  1. Giriş:

    %let dude=stuff;
    %let stuff=bEaNs;
    %put &&dude..;
    

    Çıktı:

    bEaNs.
    
  2. Giriş:

    %let __6 = 6__;
    %put __6&__6;
    

    Çıktı:

    __66__
    
  3. Giriş:

    %let i=1;
    %let hOt1Dog = BUNS;
    %put &&HoT&i.Dog are FUNS&i!");
    

    Çıktı:

    BUNS are FUNS1!")
    
  4. Giriş:

    %let x = {*':TT7d;
    %put SAS is weird.;
    

    Çıktı:

    SAS is weird.
    
  5. Giriş:

    %let var1   =  Hm?;
    %let var11 = var1;
    %let UNUSED = ;
    %put &&var11.....;
    

    Çıktı:

    Hm?....
    

    Ad eşleşmesinin açgözlü olduğu için &&var11eşleştiğini unutmayın var11. Bir olsaydı ., yani &&var1.1, o var1zaman eşleştirilirdi ve ekstra 1 herhangi bir ismin parçası olmazdı.

Bu kod golf, yani bayt en kısa çözüm kazanır!


Test örneği 1'den elde edilen çıktının süresi nasıl? &stuff.Dönemi kaldırmamalı mıyım ?
GamrCorps

@GamrCorps Belirtmeliyim: Çözünürlükte yalnızca bir sondaki nokta tüketilir.
Alex

@GamrCorps Belirtmek için düzenlenmiş ve bir test durumu olarak eklenmiştir.
Alex

yani &&&&&&&&&a......................sadece bir dönemi kaldıracak mıydı?
GamrCorps

@GamrCorps Evet.
Alex

Yanıtlar:


1

Python 3 , 354 341 336 bayt

import re
S=re.sub
def f(x):
	r=x.splitlines();C=r[-1].strip('%put ');D=0
	while D!=C:
		D=C
		for a in sorted([l.strip('%let ').replace(" ","").split(';')[0].split('=')for l in r[:-1]],key=lambda y:-len(y[0])):
			s=1
			while s:C,s=re.subn('&'+a[0]+'(\.?)',a[1]+'😍\\1',S('😍+\.([^\.])','\\1',C),0,re.I)
	return S('😍+\.?','',C)

Çevrimiçi deneyin!

düzenleme: bazı kolay kısalma

edit: [:: - 1] (5 bayt) yerine -len (...) ile sırala, Jonathan Frech sayesinde!

Ungolfed

import re
S=re.sub # new name for the function re.sub()
def f(x):
    r=x.splitlines() # input string to list of rows
    C=r[-1].strip('%put ') # get the string to put (from the last row)
    D=0
    while(D!=C): # iterate until the result does not change
        D=C
        for a in                                                                                                                    : # iterate over the list of variables
                 sorted(                                                                          ,key=lambda y:len(y[0]),reverse=1) # sort list for greediness by decreasing var.name lengths
                        [l.strip('%let ') # cut the 'let' keyword
                                         .replace(" ","") # erase spaces
                                                         .split(';')[0] # cut parts after ';'
                                                                       .split('=') # create [variable_name,value] list
                                                                                  for l in r[:-1]] # for each row but last
            s=1
            while(s): # iterate until the result does not change
                C,s=re.subn( # substitute
                            '&'+a[0]+'(\.?)', # &varname. or &varname
                                                 a[1]+'😍\\1', # to value😍. or value😍
                                                              S('😍+\.([^\.])','\\1',C), # in the string we can get from C erasing (😍's)(.) sequences if the next char is not .
                                                                                        0,re.I) # substituting is case insensitive
    return S('😍+\.?','',C) # erase smileys and one .

Python ipuçları sayfasında çok şey almanızı öneririm . Bileşik olmayan deyim birleştirme ( ;), parantez azaltma ( if(...)-> if ...) ve liste işlemleri ( ,reverse=1-> [::-1]) gibi önemsiz optimizasyonlar bazı baytları kolayca kaydedebilir.
Jonathan Frech

Teşekkürler! Daha önce okumuştum, ama uzun zaman önceydi ve bazı numaralar unuttum.
mmuntag

Rica ederim. len(y[0]))[::-1]olabilir -len(y[0])).
Jonathan Frech
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.