Giải quyết các biến macro của SAS


13

Các ngôn ngữ lập trình SAS là một phiền phức, cổ ngôn ngữ có niên đại đến 1966 đó là vẫn còn sử dụng ngày nay. Trình biên dịch gốc được viết bằng PL / I và thực sự phần lớn cú pháp xuất phát từ PL / I. SAS cũng có một tiền xử lý ngôn ngữ macro mà xuất phát từ đó PL / I là tốt. Trong thử thách này, bạn sẽ diễn giải một số yếu tố đơn giản của ngôn ngữ macro SAS.

Trong ngôn ngữ macro của SAS, các biến macro được xác định bằng cách sử dụng %lettừ khóa và in vào nhật ký được thực hiện với %put. Báo cáo kết thúc bằng dấu chấm phẩy. Dưới đây là một số ví dụ:

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

Tên biến macro không phân biệt chữ hoa chữ thường và luôn khớp với biểu thức chính quy /[a-z_][a-z0-9_]*/i. Đối với mục đích của thử thách này, chúng tôi sẽ nói như sau:

  • Biến vĩ mô chỉ có thể giữ giá trị bao gồm toàn bộ các ký tự ASCII in trừ ; , &%
  • Sẽ không có khoảng trắng ở đầu hoặc cuối trong các giá trị
  • Các giá trị sẽ không bao giờ dài hơn 255 ký tự
  • Giá trị có thể trống
  • Chân đế và dấu ngoặc kép trong các giá trị có thể không thể so sánh được
  • Có thể có bất kỳ khoảng không gian trước và sau khi =trong %lettuyên bố và không gian này nên bỏ qua
  • Có thể có bất kỳ dung lượng nào trước thiết bị đầu cuối ;trong %letcâu lệnh và không gian này tương tự nên được bỏ qua

Khi một biến vĩ mô được gọi, chúng ta nói nó "giải quyết" giá trị của nó. Các biến vĩ mô được giải quyết bằng cách thêm trước &. Có một dấu vết tùy chọn. biểu thị sự kết thúc của định danh. Ví dụ,

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

ghi The value of x is 5.vào nhật ký. Lưu ý rằng hai giai đoạn là bắt buộc vì một giai đoạn duy nhất sẽ được sử dụng &X.và giải quyết 5. Cũng lưu ý rằng mặc dù chúng tôi đã định nghĩa xbằng chữ thường, &Xcũng giống như &xvì tên biến macro không phân biệt chữ hoa chữ thường.

Đây là nơi mà nó trở nên khó khăn. Nhiều &s có thể được xâu chuỗi lại với nhau để giải quyết các biến và &s ở cùng một mức độ phân giải lồng nhau cùng một lúc. Ví dụ,

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

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

Trong cùng & giải quyết đầu tiên, và giải quyết tiếp tục ra bên ngoài. Kết hợp tên biến được thực hiện một cách tham lam. Trong %putcâu lệnh thứ hai , bộ xử lý thực hiện các bước sau:

  1. &i quyết tâm 1 , và hàng đầu trong cùng &được tiêu thụ, mang lại cho chúng tôi&&coolbeans1
  2. &coolbeans1quyết tâm broseph, cho chúng tôi&broseph
  3. &broseph quyết tâm 5 .

Nếu có dấu . s , chỉ một cái duy nhất .được tiêu thụ ở độ phân giải, ngay cả khi có nhiều &s.

Bài tập

Đưa ra từ 1 đến 10 %letcâu cách nhau bởi dòng mới và một câu%put câu lệnh, in hoặc trả về kết quả của %putcâu lệnh. Đầu vào có thể được chấp nhận theo bất kỳ cách tiêu chuẩn nào.

Bạn có thể giả định rằng đầu vào sẽ luôn hợp lệ và các %letcâu lệnh sẽ đi trước%put câu lệnh. Các biến được định nghĩa sẽ không được xác định lại trong các %letcâu lệnh sau .

Nếu thực sự chạy trong SAS, sẽ không có vấn đề gì với các biến giải quyết thành các biến không tồn tại và mọi thứ sẽ đúng về mặt cú pháp như được mô tả ở trên.

Ví dụ

  1. Đầu vào:

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

    Đầu ra:

    bEaNs.
    
  2. Đầu vào:

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

    Đầu ra:

    __66__
    
  3. Đầu vào:

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

    Đầu ra:

    BUNS are FUNS1!")
    
  4. Đầu vào:

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

    Đầu ra:

    SAS is weird.
    
  5. Đầu vào:

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

    Đầu ra:

    Hm?....
    

    Lưu ý rằng &&var11khớp var11từ khi khớp tên là tham lam. Nếu đã có một ., tức là &&var1.1, thì var1sẽ được khớp và thêm 1 sẽ không là một phần của bất kỳ tên nào.

Đây là mã golf, vì vậy giải pháp ngắn nhất tính bằng byte sẽ thắng!


Làm thế nào để đầu ra từ trường hợp thử nghiệm 1 có một khoảng thời gian? Không nên &stuff.xóa thời gian?
GamrCorps 23/2/2016

@GamrCorps Tôi nên chỉ định: Chỉ một khoảng thời gian duy nhất được sử dụng trong độ phân giải.
Alex A.

@GamrCorps Đã chỉnh sửa để chỉ định và thêm nó dưới dạng trường hợp thử nghiệm.
Alex A.

Vì vậy, &&&&&&&&&a......................vẫn sẽ chỉ loại bỏ một thời gian?
GamrCorps 23/2/2016

@GamrCorps Có.
Alex A.

Câu trả lời:


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)

Hãy thử trực tuyến!

chỉnh sửa: một số rút ngắn dễ dàng

chỉnh sửa: sắp xếp ngược theo -len (...) thay vì [:: - 1] (5 byte), nhờ Jonathan Frech!

Ung dung

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 .

Tôi sẽ đề nghị dùng rất nhiều tại trang thủ thuật Python . Tối ưu hóa tầm thường như ghép câu lệnh không ghép ( ;), giảm dấu ngoặc đơn ( if(...)-> if ...) và thao tác danh sách ( ,reverse=1-> [::-1]) có thể dễ dàng lưu một số byte.
Jonathan Frech

Cảm ơn! Tôi đã đọc nó trước đây, nhưng đã lâu rồi và tôi quên một số mánh khóe.
mmuntag

Không có gì. len(y[0]))[::-1]có thể -len(y[0])).
Jonathan Frech
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.