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합니다.

까다로운 곳이 여기에 있습니다. &변수를 해결하기 위해 여러 개의 변수를 함께 묶을 수 있으며 &, 동일한 수준의 중첩 해석에서 동시에를 해결할 수 있습니다. 예를 들어

%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.

후행 이 있으면 여러 개가 있어도 .단 하나의 .해상도 만 사용됩니다 &.

직무

%let바꿈으로 구분 된 1-10 개의 명령문과 단일 %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 다음을 지정해야합니다. 단일 후행 기간 만 해결에 소비됩니다.
Alex A.

@GamrCorps 테스트 케이스로 지정하고 추가하도록 편집되었습니다.
Alex A.

그래서 &&&&&&&&&a......................여전히 한주기를 제거 할 것인가?
GamrCorps

@GamrCorps 예.
Alex A.

답변:


1

파이썬 (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)

온라인으로 사용해보십시오!

편집 : 약간의 단축

편집 : Jonathan Frech 덕분에 [::-1] (5 바이트) 대신 -len (...)을 기준으로 역 정렬!

언 골프

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 .

파이썬 팁 페이지 에서 많은 것을 취하는 것이 좋습니다 . 비화합물 명령문 연결 ( ;), 괄호 축소 ( if(...)-> if ...) 및 목록 작업 ( ,reverse=1-> [::-1]) 과 같은 간단한 최적화를 통해 일부 바이트를 쉽게 저장할 수 있습니다.
Jonathan Frech

감사! 나는 전에 그것을 읽었지만 오래 전에, 나는 몇 가지 트릭을 잊어 버렸습니다.
mmuntag

아니에요. len(y[0]))[::-1]일 수 있습니다 -len(y[0])).
Jonathan Frech
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.