【问题标题】:How to use SAS Macro call in a %let如何在 %let 中使用 SAS 宏调用
【发布时间】:2013-07-16 08:26:37
【问题描述】:

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

【问题讨论】:

  • 给出了一些代码,但问题的本质并不清楚。请澄清您的问题。
  • 嗯,它可能更清楚,但问题标题实际上对 SAS 程序员来说非常清楚(并且是问题)。

标签: sas


【解决方案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;

【讨论】:

  • 再次感谢乔
【解决方案2】:

你有两个问题。首先,函数式宏不得包含任何数据步骤(或过程或其他任何内容)。如果确实需要执行数据步骤,则必须使用带有 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. 请勿在实际返回的行上放置分号,因为在使用函数样式的宏时可能不希望这样做。

【讨论】:

  • 乔的回答很好。给那些刚接触函数宏的人的一些提示。 1) 使用%local 语句定义所有宏变量,如下所示:%local len1 len sub pos;。 2) 请注意,Joe 使用了/* THIS STYLE FOR COMMENTING */。使用其他注释样式可能会有问题。 3) 使宏工作的秘诀是乔使用%substr 的那一行。这将解析为 bb eeeeee 保留在开放代码中。由于这就是剩下的,这就是调用宏解析的内容。 4)@Joe,您可能希望删除此行上的冒号,因为从技术上讲,冒号也会返回您不想要的。
  • 感谢乔的回答它确实有效。你能帮我做一件事吗,比如说在下面的数据步骤中使用相同的宏需要进行哪些修改。数据工作.in_data;长度 in_string $50; in_string = "a bb ccc dddd bb eeeee";输出; in_string = “aa b cc aa dee”;输出;跑步;数据工作.out_data;设置工作.in_data;长度 sub_str $50; start_word_num = -(n +1); sub_str = %xscan(in_string,'', start_word_num);跑步;过程打印;运行;
  • 感谢@RobPenridge,合并!
  • @user2592337 ,我不完全理解你的问题。请继续并将其纳入问题本身; code-in-cmets 很难阅读。
  • @Joe 我已经编辑了这个问题。我想在数据步中调用 xscan 宏。但我无法实现它。
猜你喜欢
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 1970-01-01
相关资源
最近更新 更多