Menyelesaikan variabel makro SAS

13

The SAS bahasa pemrograman adalah kikuk, kuno bahasa dating kembali ke 1966 yang masih digunakan sampai sekarang. Kompiler asli ditulis dalam PL / I , dan memang banyak sintaks yang berasal dari PL / I. SAS juga memiliki bahasa makro preprosesor yang berasal dari bahasa PL / I juga. Dalam tantangan ini, Anda akan menafsirkan beberapa elemen sederhana dari bahasa makro SAS.

Dalam bahasa makro SAS, variabel makro didefinisikan menggunakan %letkata kunci dan pencetakan ke log dilakukan dengan %put. Pernyataan diakhiri dengan titik koma. Berikut ini beberapa contohnya:

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

Nama variabel makro tidak sensitif huruf dan selalu cocok dengan persamaan reguler /[a-z_][a-z0-9_]*/i. Untuk keperluan tantangan ini, kami akan mengatakan yang berikut:

  • Variabel makro hanya bisa memegang nilai-nilai yang terdiri sepenuhnya dari karakter ASCII yang dapat dicetak kecuali ; , &, dan%
  • Tidak akan ada spasi awal atau akhir dalam nilai
  • Nilai tidak akan pernah lebih dari 255 karakter
  • Nilai mungkin kosong
  • Kurung dan tanda kutip dalam nilai mungkin tidak cocok
  • Mungkin ada jumlah ruang sebelum dan sesudah =dalam %letpernyataan dan ruang ini harus diabaikan
  • Mungkin ada jumlah ruang sebelum terminal ;dalam %letpernyataan dan ruang ini juga harus diabaikan

Ketika variabel makro dipanggil, kita katakan itu "diselesaikan" ke nilainya. Variabel makro diselesaikan dengan memprioritaskan &. Ada trailing opsional. yang menunjukkan akhir pengidentifikasi. Sebagai contoh,

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

menulis The value of x is 5.ke log. Perhatikan bahwa dua periode diperlukan karena satu periode akan dikonsumsi oleh &X.dan diselesaikan 5. Perhatikan juga bahwa meskipun kita definisikan xdalam huruf kecil, &Xsama dengan &xkarena nama variabel makro tidak sensitif huruf.

Di sinilah rumit. Beberapa &s dapat dirangkai bersama untuk menyelesaikan variabel, dan &s pada tingkat yang sama menyelesaikan sarang pada saat yang sama. Sebagai contoh,

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

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

Keputusan terdalam &pertama, dan resolusi berlanjut ke luar. Pencocokan nama variabel dilakukan dengan rakus. Dalam %putpernyataan kedua , prosesor membuat langkah-langkah berikut:

  1. &imemutuskan untuk 1, dan pimpinan terdalam &dikonsumsi, memberi kita&&coolbeans1
  2. &coolbeans1memutuskan untuk broseph, memberi kita&broseph
  3. &brosephmemutuskan untuk 5.

Jika ada trailing .s, hanya satu .yang dikonsumsi dalam resolusi, bahkan jika ada beberapa &s.

Tugas

Diberikan antara 1 dan 10 %letpernyataan yang dipisahkan oleh baris baru dan satu %putpernyataan, cetak atau kembalikan hasil %putpernyataan tersebut. Input dapat diterima dengan cara standar apa pun.

Anda dapat mengasumsikan bahwa input akan selalu valid dan bahwa %letpernyataan akan mendahului %putpernyataan. Variabel yang didefinisikan tidak akan didefinisikan ulang dalam %letlaporan nanti .

Jika benar-benar berjalan di SAS, tidak akan ada masalah dengan variabel yang menyelesaikan variabel yang tidak ada dan semuanya akan benar secara sintaksis seperti dijelaskan di atas.

Contohnya

  1. Memasukkan:

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

    Keluaran:

    bEaNs.
    
  2. Memasukkan:

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

    Keluaran:

    __66__
    
  3. Memasukkan:

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

    Keluaran:

    BUNS are FUNS1!")
    
  4. Memasukkan:

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

    Keluaran:

    SAS is weird.
    
  5. Memasukkan:

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

    Keluaran:

    Hm?....
    

    Perhatikan bahwa &&var11kecocokan var11karena pencocokan nama serakah. Jika ada ., yaitu &&var1.1, maka var1akan dicocokkan dan 1 tambahan tidak akan menjadi bagian dari nama apa pun.

Ini kode golf, jadi solusi terpendek dalam byte menang!

Alex A.
sumber
Bagaimana output dari test case 1 memiliki periode? Bukankah seharusnya &stuff.menghapus periode?
GamrCorps
@ GarrCorps Saya harus menentukan: Hanya satu periode trailing dikonsumsi dalam resolusi.
Alex A.
@GamrCorps Diedit untuk menentukan dan menambahkannya sebagai kasus uji.
Alex A.
jadi &&&&&&&&&a......................apakah hanya akan menghapus satu periode?
GamrCorps
@ GarrCorps Ya.
Alex A.

Jawaban:

1

Python 3 , 354 341 336 byte

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)

Cobalah online!

sunting: beberapa pemendekan mudah

edit: reverse sort by -len (...) bukan [:: - 1] (5 byte), terima kasih kepada Jonathan Frech!

Tidak disatukan

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 .
mmuntag
sumber
Saya akan menyarankan mengambil banyak di halaman tips Python . Optimalisasi sepele seperti gabungan pernyataan non-majemuk ( ;), pengurangan kurung ( if(...)-> if ...) dan operasi daftar ( ,reverse=1-> [::-1]) dapat dengan mudah menyimpan beberapa byte.
Jonathan Frech
Terima kasih! Saya telah membacanya sebelumnya, tapi itu sudah lama sekali, dan saya lupa beberapa trik.
mmuntag
Sama sama. len(y[0]))[::-1]bisa -len(y[0])).
Jonathan Frech