基本上我正在编写一个宏,它将把输入表,输出表和变量列表作为参数。我的变量列表显示为单个参数,我使用空格字符作为分隔符。 我的宏应该将我的列表分成nbvar宏变量,它们将包含我的(SAS)变量的名称。然后我使用datastep将我的(SAS)变量从其原始字符格式输入到数值。
这是我的代码:
%macro convert_car_to_num(input,output,listvar);
/* First I split my list into nbvar variables named var&i
%qscan to avoid macro resolution of names, not really necessary here
but still works fine. My delimiter is space character, hence
%str( ) in the %qscan*/
%let nbvar=%sysfunc(countw(&listvar));
%do i = 1 %to &nbvar;
%let var&i=%qscan(&listvar,&i,%str( ));
%end;
/*Here is my data step. &&var&i_num is resolved just fine*/
data &output;
set &input;
%do i = 1 %to &nbvar;
&&var&i.._num = input(&&var&i,BEST16.);
%end;
run;
%mend;
由于&& var& i .._ num和&& var& i已经解决,我希望我的代码能够正常工作,但我的日志显示:
varname_num
180
解析名称" varname"有下划线。我发现后有点:
错误180-322:声明无效或使用不正确。
错误的分号通常是标准错误。但我知道我的宏变量已经解决,因为mprint显示:
MPRINT(CONVERT_CAR_TO_NUM):varname_num = input(varname,BEST16。)
注意:由宏变量生成的行" VAR26"。
MPRINT(CONVERT_CAR_TO_NUM):运行;
其中varname是我列表中第26个变量的正确名称,表示分辨率工作正常。
为了让我更难以理解,我会指出相同的代码:
&&var&i.. = input(&&var&i,BEST16.);
编译,即使它没有达到预期的结果(变量仍然是char)。
同样,代码与:
相同&&var&i.._num = &&var&i;
也不编译。
我还测试过将我的宏变量的名称更改为num_&& var& i或n&& var& i,或甚至首先声明一个宏变量" name&#34 ;它包含&& var& i,都具有相同的效果。不选择与初始变量相同的名称似乎会导致代码显示180错误。
我想这个问题存在于尝试声明一个变量,知道我编写的前一个和类似的代码片段确实有效,datastep是一个比较(从变量列表中将缺失值转换为零):
data &output;
set &input;
%do i = 1 %to &nbvar;
if &&var&i = . then &&var&i = 0;
%end;
run;
但对于同一段代码,如果我尝试创建一个新变量(同样具有任何名称),写作:
if num_&&var&i = . then &&var&i = 0;
我发现自己的解析名称再次加下划线,但现在指向以下错误:
错误22-322:语法错误,期待以下之一:!,!!,&,(,*,**,+, - ,/,;,<, < =,<>,=,>,><,> =,AND,EQ,GE,GT,IN,LE,LT,MAX,MIN,NE,NG,NL,NOTIN,或, [,^ =,{,|,||,〜=。
答案 0 :(得分:1)
这是SAS无法自动取消引用值的问题。我学到的规则是,如果您的SAS代码(由MPRINT显示)看起来有效,但是您遇到错误,请尝试取消引用。
在您的情况下,请更改为:
%unquote(&&var&i.._num) = input(&&var&i,BEST16.);
使代码有效。当然根据您的评论,您可能不需要%qscan
来引入有问题的引用字符。如果您将其更改为%scan
,则无需%unquote()
,因为它不会被引用。
同意@Foxer的方法,使用单个宏变量将i_th变量存储在列表中。还建议制作这些%局部变量以避免冲突。可能是这样的:
%macro convert_car_to_num(input,output,listvar);
%local i vari;
data &output;
set &input;
%do i = 1 %to %sysfunc(countw(&listvar,%str( )));
%let vari=%scan(&listvar,&i,%str( ));
&vari._num=input(&vari,best16.);
%end;
run;
%mend;
答案 1 :(得分:0)
以下是否满足您的需求?我的猜测是你在单独的if-then-do
语句中有太多的内容:
%macro new(input,output,listvar);
data &output; set &input;
%do i=1 %to %sysfunc(countw(&listvar.));
%let var=%scan(&listvar.,&i.);
var&i._num = input(&var.,BEST16.);
%end;
run;
%mend;
%new(have,want,&listvar.);
如果你正在尝试为你正在循环的每个变量创建一个单独的宏变量,下面也可以做你想要的(虽然在这种情况下它可能不值得,但只是为其他应用程序显示另一个有用的方法):
** put variables into dataset **;
proc sql noprint;
create table vars
as select name,type
from dictionary.columns
where upcase(libname)="WORK" and
upcase(memname)="HAVE" and
type = "char";
quit;
** create total count and separate macro variable for each variable **;
data _null_; set vars end=last;
by name;
i+1;
call symputx('name'||strip(put(i,8.)), name);
if last then call symputx('count',i);
run;
%put &count.;
%put &name1.;
%put &name2.;
%put &name3.;
** loop over each variable using the total count **;
%macro new(input,output);
data &output; set &input;
%do i=1 %to &count.;
&&name&i.._num = input(&&name&i,BEST16.);
%end;
run;
%mend;
%new(have,want);