如何在%let中使用SAS Macro调用

时间:2013-07-17 16:46:41

标签: sas

我想在%let调用中使用宏,下面是宏代码以及我想如何调用它。请帮助我实现它。

%macro xscan(string, delimiter, word_number);

%let len1=%length(&string); /*Computing the length of the string*/
%let len=%eval(&len1+1);
%let sub=%scan(&string,&word_number,"&delimiter"); /*Fetch the string specified by     word_number*/

%if &word_number ge 0 %then %do;
%let pos=%index(&string,&sub); /* Locate the position while reading left to right*/
%end;

%if &word_number lt 0 %then %do;
data _null_;
pos=find("&string","&sub",-&len); /* Locate the position while reading from right to left*/
call symput("pos",pos);
run;
%end;

%let strg=%substr(&string,&pos); /* Extract the substring*/

%put the string is &strg;
%mend;

%let sub_str = %xscan(a bb ccc dddd bb eeeee, %str( ), -2);
%put The value of sub_str = &sub_str;

期望的实施:

 data work.in_data;
length in_string $50;
in_string = “a bb ccc dddd bb eeeee”; 
output;
in_string = “aa b cc aa dee”; 
output;
  run;

  data work.out_data;
set work.in_data;
length sub_str $50;
start_word_num = -(_n_ +1);
sub_str = %xscan(in_string,’ ‘, start_word_num);
  run;

  proc print; run;

2 个答案:

答案 0 :(得分:1)

你有两个问题。首先,函数式宏不得包含任何数据步骤(或procs或其他任何内容)。如果确实需要执行数据步骤,则必须将FCMP与run_macro配合使用。但是,您可以使用%SYSFUNC来完成数据步骤中的操作。

其次,您需要实际返回该值。最终宏会解析为文本,因此您需要解析

%let x = %xscan(...);

%let x = bb eeeee;

所以你需要在你的宏中将bb eeeee作为开放文本。

这应该完成两件事:

options mprint symbolgen;

%macro xscan(string, delimiter, word_number);
%local len1 len sub pos;

%let len1=%length(&string); /*Computing the length of the string*/
%let len=%eval(&len1+1);
%let sub=%scan(&string,&word_number,"&delimiter"); /*Fetch the string specified by     word_number*/

%if &word_number ge 0 %then %do;
%let pos=%index(&string,&sub); /* Locate the position while reading left to right*/
%end;

%else %if &word_number lt 0 %then %do;
%let pos=%sysfunc(find(&string,&sub,-&len)); /* Locate the position while reading from right to left*/
%end;

%substr(&string,&pos) /* Extract the substring*/

%mend;

%let sub_str = %xscan(a bb ccc dddd bb eeeee, %str( ), -2);
%put The value of sub_str = &sub_str;

(注意,我不一定知道这会做你真正想要的,但它会做代码似乎正在做的事情。)

功能式宏的一些提示,由Rob Penridge提供:

  1. 使用%local语句定义所有宏变量,如下所示:%local len1 len sub pos;。这样就不会覆盖全局宏变量。
  2. 使用/ *这个样式进行评论* /。使用其他评论样式可能会导致该行结束。
  3. 使宏工作的秘诀是最后使用%substr的行。这解决了bb eeeeee留在开放代码中。由于这就是剩下的一切,这就是调用宏所解决的问题。
  4. 不要在实际返回的行上放置分号,因为在使用函数式宏时可能不合适。

答案 1 :(得分:1)

我发布了一个新的答案,因为另一个答案回答了一个稍微不同的问题。

在这里,您的宏实际上是用于执行数据步骤技术,而不是宏技术。您不能(轻松)使用宏来编辑变量内容;宏旨在编写SAS代码,而不是修改变量。您可以使用PROC FCMP来解决这个问题,如果我有更多的时间,我可能会这样做,但是现在这里只是数据步骤技术和普通(非功能)宏的正确解决方案。

首先,编写数据步骤技术来完成它。这是一个相当混乱但有效的解决方案。它只适用于负start_word_num;如果需要左或右,则需要对循环参数进行一些修改。我建议将此作为起点,并根据您的需求进行改进。

data work.out_data;
set work.in_data;
length sub_str $50;
start_word_num = -(_n_ +1);
do _t = countc(trimn(in_string),' ')+1 to countc(trimn(in_string),' ')+start_word_num+2 by -1;
    sub_str = catx(' ',scan(in_string,_t,' '),sub_str);
    put _t= sub_str=;
end;
put in_string= sub_str=;
run;

现在,将循环移动到宏中。

%macro xscan(word_num, initial_string, result);
&result.=' ';
do _t = countc(trimn(&initial_string.),' ')+1 to countc(trimn(&initial_string.),' ')+&word_num.+2 by -1;
    &result. = catx(' ',scan(&initial_string.,_t,' '),&result.);
end;
%mend xscan;


data work.out_data;
set work.in_data;
length sub_str $50;
start_word_num = -(_n_ +1);
%xscan(start_word_num,in_string,sub_str);
put in_string= sub_str=;
run;