Разрешить макропеременные 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 символов
  • Значения могут быть пустыми
  • Скобки и кавычки в значениях могут не совпадать
  • До и после оператора =in может быть любое количество места, %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 */

&Сначала внутреннее решение, а разрешение продолжается вовне. Соответствие имени переменной выполняется жадно. Во втором %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.1, тогда var1было бы сопоставлено, и дополнительный 1 не был бы частью какого-либо имени.

Это код гольф, поэтому выигрывает самое короткое решение в байтах!

Алекс А.
источник
Как выходные данные из тестового примера 1 имеют период? Не должны &stuff.удалить период?
GamrCorps
@GamrCorps Я должен указать: в разрешении используется только один конечный период.
Алекс А.
@GamrCorps Отредактировано, чтобы указать и добавить его в качестве контрольного примера.
Алекс А.
так &&&&&&&&&a......................все равно только удалить один период?
GamrCorps
@GamrCorps Да.
Алекс А.

Ответы:

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 байт), благодаря Джонатану Фреху!

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 .
mmuntag
источник
Я бы посоветовал взять много на странице советов по Python . Тривиальная оптимизация, такая как составная инструкция concatenation ( ;), сокращение скобок ( if(...)-> if ...) и операции со списками ( ,reverse=1-> [::-1]), могут легко сохранить некоторые байты.
Джонатан Фрех
Благодарность! Я читал это раньше, но это было давно, и я забыл некоторые хитрости.
ммунтаг
Добро пожаловать. len(y[0]))[::-1]может быть -len(y[0])).
Джонатан Фрех