1

我想在 %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;
4

2 回答 2

1

你有两个问题。首先,函数式宏不得包含任何数据步骤(或过程或其他任何内容)。如果确实需要执行数据步骤,则必须使用带有 run_macro 的 FCMP。但是,您可以在这里使用%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. 不要在实际返回的行上放置分号,因为在使用函数式宏时可能不希望这样做。
于 2013-07-17T17:29:24.627 回答
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;
于 2013-07-18T15:27:54.837 回答