解决SAS宏变量


13

SAS编程语言是笨重的,古老的语言可以追溯到1966年的今天这仍然在使用。原始的编译器是用PL / I编写的,实际上许多语法都来自PL / I。SAS还具有从PL / I的语言衍生而来的预处理器宏语言。在这个挑战中,您将解释SAS宏语言的一些简单元素。

在SAS宏语言中,宏%let关键字是使用关键字定义的,并使用进行打印到日志%put。语句以分号结尾。这里有些例子:

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

宏变量名称不区分大小写,并且始终与正则表达式匹配/[a-z_][a-z0-9_]*/i。出于此挑战的目的,我们将讲以下内容:

  • 宏变量只能保存完全由可打印ASCII字符组成的值,,和除外 ;&%
  • 值中将没有前导或尾随空格
  • 值的长度不得超过255个字符
  • 值可能为空
  • 值中的方括号和引号可能不匹配
  • 可以有任何空间量前后=%let语句和这个空间应该被忽略
  • 可以有空间的任何数量的终端之前;%let声明,这个空间应该同样被忽略

当调用宏变量时,我们说它“解析”为其值。宏变量通过前置来解决&。有一个可选的结尾.表示标识符的末尾。例如,

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

写入The value of x is 5.日志。请注意,需要两个期间,因为单个期间将被消耗&X.并解析为5。还要注意,即使我们x以小写字母定义,&X也是如此,&x因为宏变量名称不区分大小写。

这就是棘手的地方。&可以将多个s串在一起以解析变量,并且&处于同一嵌套级别的s可以同时解析。例如,

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

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

最里面的&s首先解析,而解析继续向外扩展。变量名匹配是贪婪地完成的。在第二条%put语句中,处理器执行以下步骤:

  1. &i解析为1,并且&消耗了最里面的领导力,这给了我们&&coolbeans1
  2. &coolbeans1解决broseph,给我们&broseph
  3. &broseph决定解决5

如果存在尾随的.s,.则即使有多​​个&s 也仅消耗一个分辨率。

任务

给定1到10个%let由换行符分隔的语句和一个%put语句,则打印或返回%put语句的结果。可以以任何标准方式接受输入。

您可以假定输入将始终有效,并且%let语句将位于该%put语句之前。定义的变量将不会在以后的%let语句中重新定义。

如果实际在SAS中运行,则将变量解析为不存在的变量将不会有问题,并且如上所述,所有语法都将正确。

例子

  1. 输入:

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

    输出:

    bEaNs.
    
  2. 输入:

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

    输出:

    __66__
    
  3. 输入:

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

    输出:

    BUNS are FUNS1!")
    
  4. 输入:

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

    输出:

    SAS is weird.
    
  5. 输入:

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

    输出:

    Hm?....
    

    请注意,由于名称匹配是贪婪的,因此&&var11匹配var11。如果存在.,即&&var1.1var1则将被匹配,多余的1将不属于任何名称。

这是代码高尔夫,所以最短的解决方案以字节为单位!


测试用例1的输出如何有一个周期?不应该&stuff.删除期限吗?
GamrCorps '16

@GamrCorps我应该指定:在解析中只消耗了一个尾随周期。
Alex A.

@GamrCorps编辑为指定并添加为测试用例。
Alex A.

所以&&&&&&&&&a......................仍然只删除一个期间?
GamrCorps '16

@GamrCorps是的。
Alex A.

Answers:


1

Python 3中354个 341 336字节

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)

在线尝试!

编辑:一些简单的缩短

编辑:通过-len(...)而不是[::-1](5个字节)进行反向排序,这要归功于乔纳森·弗雷希(Jonathan Frech)!

不打高尔夫球

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技巧页面上花很多时间。非复合语句串联(;),括号减少(if(...)-> if ...)和列表操作(,reverse=1-> [::-1])等简单的优化可以轻松地节省一些字节。
乔纳森·弗雷希

谢谢!我以前看过它,但是很久以前,我忘记了一些技巧。
mmuntag '18

别客气。len(y[0]))[::-1]可以-len(y[0]))
乔纳森·弗雷希
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.