0

我有一个需要两个参数的宏——一个可以包含破折号和句点的字符串,以及一个相同字符串的清理版本,其中任何破折号和句点都被下划线替换。

以下作品:

%let foo = abc.def;

%mymacro(firstpar = &foo, secondpar=%sysfunc(translate(&foo,"__","-.")));

%let foo = abc-def;

%mymacro(firstpar = &foo, secondpar=%sysfunc(translate(&foo,"__","-.")));

...但是我如何遍历一长串此类变量?是否有一些标准的习惯用法可以一次将列表的元素分配给一个占位符变量然后评估命令,或者直接将它们替换为命令字符串(但在我明确要求之前不评估它)?

我尝试使用%DO_WHILE宏库,只要&foos 不包含标点符号,它就可以很好地工作。如果他们这样做了,它就会失败,并且我尝试过的任何引用组合都不能让它发挥作用。

我的实际宏太长且令人费解,无法在此处发布。希望这个一般性问题足够清楚,可以回答:

“重复调用一个宏的推荐策略是什么,它的一次性调用看起来像%mymacro(firstpar = &foo, secondpar=%sysfunc(translate(&foo,"__","-.")));,并且你有一个大的值列表foo?”

或者换一种说法:“SAS 中最接近 Rparse()deparse()功能的东西是什么?”

4

3 回答 3

2

我无法与 R 的解析和解析相关,因为我不熟悉它们。但是,我只需传入第一个参数并在宏中创建第二个宏变量。请参见下文,FIRSTPAR 与您在示例中使用的一样。我包含一个 TRANSLATE 参数,其中包含应替换的字符(默认为“。”):

%macro mymacro(firstpar=,translate=.);

  data _null_;
    firstpar="&firstpar";
    translate="&translate";
    secondpar="&firstpar";
    subi=1;
    do while(length(translate)>=subi);
      secondpar=tranwrd(secondpar,substr(translate,subi,1),"_");
      subi+1;
    end;
    call symput('secondpar',secondpar);
  run;
  %put &secondpar;
%mend mymacro;

替换句点和破折号:

%mymacro(firstpar=abc-de-fg.hi-.k,translate=.-)

替换句点、破折号和逗号:

%mymacro(firstpar=%str(abc-de,fg.hi,.k),translate=%str(.-,))

这两个示例将 SECONDPAR 宏变量输出到日志,如下所示:

abc_de_fg_hi__k
于 2012-12-03T09:24:02.000 回答
0

您在这里提到了“列表”,因此该方法将取决于您如何将此列表解析为宏。如果列表已经是可以直接用作宏变量的形式,例如

%let foo = abc-def abc-d-af abd-c-dgf; 

这里各个参数由空格分隔。宏变量包含所有内容。然后你可以一一提取参数:

 %macro mymacro(firstpar = &foo, secondpar=%sysfunc(translate(&foo,"__","-.")));
   %do i = 1 %to %sysfunc(countw(&foo,' '));
          %let p1 = %scan(&foo, &i, ' ');
          %let p2 = %scan(&secondpar, &i, ' ');
          *<original macro statements>*
   %end;

用于COUNTW获取参数个数,并SCAN获取这些参数。

如果需要先导入列表。还有额外的步骤:

 data tmp;
 input foo $;
 datalines;
 abc-def
 abcd-def
 abc-d-af
 ;
 run;

 proc sql noprint;
   select foo into :foo separated by ' ' from tmp;
 quit;

现在列表已存储到foo,由空格分隔。然后就可以解析成上面的宏了。

于 2012-12-03T10:49:07.573 回答
0

我认为一个简单的问题是,您如何从现有数据中重复调用宏。我会先说,通常你不这样做 - 你通常只是在普通的 SAS 代码中做任何事情。但是你没有给我们任何信息,所以也许你有充分的理由重复调用宏(我有时确实会这样做,尽管通常会试图避免它)。

我会将上面 DavB 的答案合并到这个答案中 - 不要将两个值都作为参数,只使用第一个参数,然后在宏内部将其转换为第二个。

大约有十几种方法可以创建数据驱动的宏调用;这里有三个。

%macro foo(param=);
%let second_param=%sysfunc(translate(&param,"___","-.a"));
%put &param &second_param;
%mend foo;


*Method 1: Call Execute.  This puts code in a queue to execute after the data step completes.  
    This has some advantages, namely that you can build code easily and can modify it with data step functions, 
    and some disadvantages, namely that some timing issues (when things happen internal to SAS) exist 
    and can be difficult to remember/work around.  Not used all that often as a result of those timing issues 
    but for simple things can be useful.;
data _null_;
set sashelp.class;
mcall = cats('%foo(param=',name,')');
call execute(mcall);
run;

*Method 2: PROC SQL select into.  This creates a list and stores it in a macro variable.  
    Quick and easy (much shorter code-wise) compared to the other solutions, but has one significant limitation:
    a hard limit to how many total characters can be stored in a macro variable (I forget exactly how much, but around 20,000).
    So if you are calling the macro a thousand or more times this might fail - it writes a warning to the log if so.
    Use NOPRINT with PROC SQL unless you want to see what is generated.;
proc sql;
select cats('%foo(param=',name,')') into :mcalllist separated by ' ' from sashelp.class;
quit;
&mcalllist;

*Method 3: Include file generation.  This creates an actual text file with your code in it, then you include that code.
    In some ways the most transparent - you can easily debug the code - but also a lot of lines of code to write comparatively.
    Does not have the length limitation of the PROC SQL method, although it does have the normal limitations of included code.
    The temp file is written to your WORK directory, so you can navigate to that to see the contents, and/or use a non-TEMP file
    and write it out to a directory of your choosing in order to see it.
;

filename foo temp;
data _null_;
file foo;
set sashelp.class;
mcall = cats('%foo(param=',name,')');
put mcall $;
run;
%include foo;
于 2012-12-03T21:10:33.927 回答