Risolvi le variabili macro SAS


13

Il linguaggio di programmazione SAS è un linguaggio volgare e arcaico risalente al 1966 che è ancora in uso oggi. Il compilatore originale è stato scritto in PL / I , e in effetti gran parte della sintassi deriva da PL / I. SAS ha anche un preprocessore macro-linguaggio che deriva da quella di PL / I pure. In questa sfida, interpreterai alcuni semplici elementi del linguaggio macro SAS.

Nel linguaggio macro SAS, le variabili macro vengono definite utilizzando la %letparola chiave e la stampa viene eseguita con il registro %put. Le dichiarazioni terminano con punto e virgola. Ecco alcuni esempi:

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

I nomi delle variabili macro non fanno distinzione tra maiuscole e minuscole e corrispondono sempre all'espressione regolare /[a-z_][a-z0-9_]*/i. Ai fini di questa sfida, diremo quanto segue:

  • Variabili macro possono contenere solo valori costituiti interamente di caratteri ASCII stampabili ad eccezione ; , &e%
  • Non ci saranno spazi iniziali o finali nei valori
  • I valori non saranno mai più lunghi di 255 caratteri
  • I valori possono essere vuoti
  • Le parentesi e le virgolette nei valori possono essere senza pari
  • Ci può essere qualsiasi quantità di spazio prima e dopo =l' %letistruzione in e questo spazio deve essere ignorato
  • Non ci può essere una qualsiasi quantità di spazio prima che il terminale ;nella %letdichiarazione e questo spazio devono anche ignorato

Quando viene chiamata una variabile macro, diciamo che "si risolve" al suo valore. Le variabili macro vengono risolte anteponendo &. Esiste un finale facoltativo. che indica la fine dell'identificatore. Per esempio,

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

scrive The value of x is 5.nel registro. Si noti che sono richiesti due periodi perché un singolo periodo verrà utilizzato &X.e risolto 5. Si noti inoltre che, sebbene sia stato definito xin minuscolo, &Xè uguale al &xfatto che i nomi delle variabili macro non fanno distinzione tra maiuscole e minuscole.

Ecco dove diventa difficile. Più &s possono essere uniti per risolvere le variabili e &allo stesso livello di nidificazione allo stesso tempo. Per esempio,

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

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

I più &interni si risolvono per primi e la risoluzione continua verso l'esterno. La corrispondenza dei nomi delle variabili viene eseguita avidamente. Nella seconda %putistruzione, il processore procede come segue:

  1. &isi risolve 1e il vantaggio più profondo &viene consumato, dandoci&&coolbeans1
  2. &coolbeans1si risolve broseph, dandoci&broseph
  3. &brosephsi risolve in 5.

Se ci sono .s finali , solo uno .viene consumato in risoluzione, anche se ce ne sono più& .

Compito

Dato tra 1 e 10 %letistruzioni separate da newline e una singola %putistruzione, stampa o restituisce il risultato di%put dell'istruzione. L'ingresso può essere accettato in qualsiasi modo standard.

Si può presumere che l'input sia sempre valido e che le %letistruzioni precedano l' %putistruzione. Le variabili definite non verranno ridefinite nelle %letistruzioni successive .

Se effettivamente eseguito in SAS, non ci sarebbero problemi con le variabili che si risolvono in variabili che non esistono e tutto sarà sintatticamente corretto come descritto sopra.

Esempi

  1. Ingresso:

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

    Produzione:

    bEaNs.
    
  2. Ingresso:

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

    Produzione:

    __66__
    
  3. Ingresso:

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

    Produzione:

    BUNS are FUNS1!")
    
  4. Ingresso:

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

    Produzione:

    SAS is weird.
    
  5. Ingresso:

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

    Produzione:

    Hm?....
    

    Nota che le &&var11corrispondenze var11poiché la corrispondenza dei nomi è avida. Se ci fosse stato un ., cioè &&var1.1, allora var1sarebbe abbinato e l'1 in più non farebbe parte di nessun nome.

Questo è il golf del codice, quindi vince la soluzione più breve in byte!


In che modo l'output del test case 1 ha un punto? Non è necessario &stuff.rimuovere il periodo?
GamrCorps,

@GamrCorps Dovrei specificare: nella risoluzione viene consumato solo un singolo periodo finale.
Alex A.

@GamrCorps Modificato per specificarlo e aggiunto come test case.
Alex A.

quindi &&&&&&&&&a......................rimuoverebbe solo un periodo?
GamrCorps,

@GamrCorps Sì.
Alex A.

Risposte:


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)

Provalo online!

modifica: qualche accorciamento facile

modifica: invertire l'ordinamento per -len (...) anziché [:: - 1] (5 byte), grazie a Jonathan Frech!

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 .

Vorrei suggerire di prendere molto alla pagina dei suggerimenti di Python . Ottimizzazioni banali come la concatenazione di istruzioni non composte ( ;), la riduzione delle parentesi ( if(...)-> if ...) e le operazioni di elenco ( ,reverse=1-> [::-1]) possono facilmente salvare alcuni byte.
Jonathan Frech,

Grazie! L'ho letto prima, ma è stato tanto tempo fa e ho dimenticato alcuni trucchi.
mmuntag

Prego. len(y[0]))[::-1]può essere -len(y[0])).
Jonathan Frech,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.