Résoudre les variables de macro SAS


13

Le langage de programmation SAS est un langage maladroit et archaïque datant de 1966 qui est toujours utilisé aujourd'hui. Le compilateur d'origine a été écrit en PL / I , et en effet une grande partie de la syntaxe dérive de PL / I. SAS a également un langage macro préprocesseur qui de dérive de celle de PL / I ainsi. Dans ce défi, vous allez interpréter quelques éléments simples du langage macro SAS.

Dans le langage de macro SAS, les variables de macro sont définies à l'aide du %letmot - clé et l'impression dans le journal se fait avec %put. Les déclarations se terminent par des points-virgules. Voici quelques exemples:

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

Les noms de variables de macro ne respectent pas la casse et correspondent toujours à l'expression régulière /[a-z_][a-z0-9_]*/i. Aux fins de ce défi, nous dirons ce qui suit:

  • Les variables de macro ne peuvent contenir des valeurs composées uniquement de caractères ASCII imprimables sauf ; , &et%
  • Il n'y aura pas d'espaces de début ou de fin dans les valeurs
  • Les valeurs ne dépasseront jamais 255 caractères
  • Les valeurs peuvent être vides
  • Les crochets et les guillemets dans les valeurs peuvent être inégalés
  • Il peut y avoir n'importe quelle quantité d'espace avant et après le =dans l' %letinstruction et cet espace doit être ignoré
  • Il peut y avoir n'importe quelle quantité d'espace avant le terminal ;dans l' %letinstruction et cet espace doit également être ignoré

Lorsqu'une macro variable est appelée, nous disons qu'elle "résout" sa valeur. Les variables de macro sont résolues par préfixation &. Il y a une fin facultative. qui indique la fin de l'identifiant. Par exemple,

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

écrit The value of x is 5.dans le journal. Notez que deux périodes sont nécessaires car une seule période sera consommée par &X.et résolu 5. Notez également que même si nous avons défini xen minuscules, &Xc'est la même chose que &xparce que les noms de variables de macro ne respectent pas la casse.

Voici où cela devient difficile. Plusieurs &s peuvent être liés ensemble pour résoudre des variables, et &s au même niveau de résolution d'imbrication en même temps. Par exemple,

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

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

Les plus intimes se &résolvent en premier et la résolution se poursuit vers l'extérieur. La correspondance des noms de variables se fait avec avidité. Dans la deuxième %putinstruction, le processeur effectue les étapes suivantes:

  1. &ise résout à 1, et le plus intime leader &est consommé, nous donnant&&coolbeans1
  2. &coolbeans1décide de brosephnous donner&broseph
  3. &brosephdécide de 5.

S'il y a des .s finaux , un seul .est consommé en résolution, même s'il y a plusieurs &s.

Tâche

Étant donné entre 1 et 10 %letinstructions séparées par des retours à la ligne et une seule %putinstruction, imprimez ou renvoyez le résultat de l' %putinstruction. L'entrée peut être acceptée de n'importe quelle manière standard.

Vous pouvez supposer que l'entrée sera toujours valide et que les %letinstructions précéderont l' %putinstruction. Les variables définies ne seront pas redéfinies dans les %letinstructions ultérieures .

S'ils s'exécutent réellement dans SAS, il n'y aurait aucun problème avec la résolution des variables en variables qui n'existent pas et tout sera syntaxiquement correct comme décrit ci-dessus.

Exemples

  1. Contribution:

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

    Production:

    bEaNs.
    
  2. Contribution:

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

    Production:

    __66__
    
  3. Contribution:

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

    Production:

    BUNS are FUNS1!")
    
  4. Contribution:

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

    Production:

    SAS is weird.
    
  5. Contribution:

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

    Production:

    Hm?....
    

    Notez que &&var11correspond var11car l'appariement de nom est gourmand. S'il y avait eu un ., c'est-à-dire &&var1.1, alors il y var1aurait correspondance et le 1 supplémentaire ne ferait partie d'aucun nom.

C'est le golf de code, donc la solution la plus courte en octets gagne!


Comment la sortie du scénario de test 1 a-t-elle une période? Ne devrait pas &stuff.supprimer la période?
GamrCorps

@GamrCorps Je dois préciser: une seule période de fin est consommée en résolution.
Alex A.

@GamrCorps Modifié pour le spécifier et l'ajouter comme cas de test.
Alex A.

donc &&&&&&&&&a......................serait encore seulement enlever une période?
GamrCorps

@GamrCorps Oui.
Alex A.

Réponses:


1

Python 3 , 354 341 336 octets

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)

Essayez-le en ligne!

modifier: un raccourcissement facile

edit: tri inversé par -len (...) au lieu de [:: - 1] (5 octets), merci à Jonathan Frech!

Non golfé

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 .

Je suggérerais d'en prendre beaucoup sur la page des conseils Python . Les optimisations triviales telles que la concaténation des instructions non composées ( ;), la réduction des parenthèses ( if(...)-> if ...) et les opérations de liste ( ,reverse=1-> [::-1]) peuvent facilement enregistrer certains octets.
Jonathan Frech

Merci! Je l'ai déjà lu, mais c'était il y a longtemps et j'ai oublié quelques trucs.
mmuntag

Je vous en prie. len(y[0]))[::-1]peut être -len(y[0])).
Jonathan Frech
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.