Розв’яжіть макрозмінні 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 */

Сама внутрішня &сек рішучість першої, а дозвіл продовжує назовні. Зміна відповідності змінних імен робиться жадібно. У другому %putтвердженні процесор робить такі кроки:

  1. &iвирішується на 1, і найпотужніше провідне &споживається, даючи нам&&coolbeans1
  2. &coolbeans1вирішує broseph, даруючи нам&broseph
  3. &brosephвирішує до 5.

Якщо є кінцеві .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 байт), завдяки Джонатану Фреху!

Безумовно

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

Будь ласка. len(y[0]))[::-1]може бути -len(y[0])).
Джонатан Фрех
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.