我试图在数据步骤中生成代码,然后将代码传递给宏,然后运行代码。我知道,它有点迂回,但我无法想到更好的解决方案,因为我的代码内容基于数据集中的内容。
在我的数据集中," test2",我只对变量"语句"进行了一次观察,它等于
J 1 =输入(J,anydtdtm。);下降j;重命名j1 = j; K1 =输入(K,anydtdtm。);下降k;重命名k1 = k; L1 =输入(1,anydtdtm。);下降l;重命名l1 = l;
我有一个基本上是
的宏%macro dummy(ds,statements);
data &ds.2;
set &ds.;
&statements.
run;
%mend;
然后我使用call执行以下命令:
data test3;
set test2;
call execute('%dummy('||strip(ds)||','||strip(statement)||')');
run;
但是我收到以下错误:
ERROR: The keyword parameter J1 was not defined with the macro.
显然SAS正在解释我的" ="签名作为宏变量的内容以外的东西。我尝试使用%str并将我的调用执行更改为:
data test3;
set test2;
call execute('%dummy('||strip(ds)||','||%str(strip(statement))||')');
run;
但它没有用。有人有什么想法吗?
感谢您的帮助!!
答案 0 :(得分:4)
首先,如果您使用命名参数,这不是问题。
%macro dummy(ds=,statements=);
data &ds.2;
set &ds.;
&statements.
run;
%mend;
data class;
set sashelp.class;
run;
data fixes;
infile datalines truncover;
length statement $40 all_statements $512 execstr $1024;
do _n_ = 1 to 2;
input @1 statement $40.;
all_statements=catx(';',all_statements,statement);
end;
put all_statements;
execstr = cats('%dummy(ds=class,statements=',all_statements,';)');
call execute(execstr);
datalines;
if sex='M' then m_height=height
if sex='F' then f_height=height
;;;;
run;
然后SAS看到命名参数等号,并且知道从那个到下一个逗号的所有内容都是该参数的值。
当然,如果你有逗号,你仍然需要做点什么。这是你接近但不完全的地方。 %str
需要引用宏调用,而不是宏调用的构造 - 换句话说,它需要在引号内。
data fixes;
infile datalines truncover;
length statement $40 all_statements $512 execstr $1024;
do _n_ = 1 to 2;
input @1 statement $40.;
all_statements=catx(';',all_statements,statement);
end;
put all_statements;
execstr = cats('%dummy(ds=class,statements=%nrstr(',all_statements,';))');
call execute(execstr);
datalines;
if sex in ('M','F') then mfheight=height
if sex='F' then f_height=height
;;;;
run;
我个人喜欢%nrstr
,因为它也消除了那些讨厌的&符号和百分号,这可能有一些意义。
将其置于此处意味着当SAS运行该调用执行时,它会传递%str
或%nrstr
并引用正在发送的值。
当你在另一个地方有它时:
execstr = cats('%dummy(ds=class,statements=',%nrstr(all_statements),';)');
受保护/引用的内容不是all_statements
内的文字,而是字符all_statements
(换句话说,变量名称)。这对你来说并没有多大帮助。
答案 1 :(得分:3)
传递等号非常简单,只需在调用中使用命名参数即可。
die()
它正在传递非常难的半冒号。为此,您需要引用宏调用中的值。您可以使用宏引用来执行此操作,但我发现使用常规引号并在宏代码中删除它们更容易。
让宏使用%dummy(ds=x,statement=x=2)
功能删除可能围绕参数值的任何引号。
DEQUOTE()
让我们将您的示例语句设置为数据集。
%macro dummy(ds,statements);
data &ds.2;
set &ds.;
%sysfunc(dequote(&statements))
run;
%mend;
这些陈述的一些样本数据。
data have;
ds='x';
statements=
'j1=input(j,anydtdtm.); drop j; rename j1=j;'
|| 'k1=input(k,anydtdtm.); drop k; rename k1=k;'
|| 'l1=input(l,anydtdtm.); drop l; rename l1=l;'
;
run;
现在您可以使用数据集生成呼叫。使用data x;
j='01JAN1960';
k='10FEB2010';
l='2014-05-01';
run;
函数将语句括在引号中。
QUOTE()
这是LOG。
options mprint;
data _null_;
set have ;
call execute(cats('%nrstr(%dummy)(',ds,',',quote(trim(statements)),')'));
run;
答案 2 :(得分:1)
这是在文件中生成代码更容易,然后使用%include语句提交代码的情况之一:
filename tempsas temp;
data test3;
set test2;
file tempsas;
put
'data ' ds +(-1) '2;' /
' set ' ds ';' /
' ' statements /
'run;'
;
run;
然后您可以通过查看文件开始(在编辑窗口中使用' include tempsas'命令),提交一个datastep以查看是否一切顺利,以及当您确定所有内容都是好的,你把
%include tempsas;
在原始代码中。
答案 3 :(得分:0)
在这里阅读评论后(感谢您的帮助!),我想出了一个不同的解决方案(虽然更改我的宏以接受命名参数也有效):
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';")
System.setProperty("jenkins.model.DirectoryBrowserSupport.CSP", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';”)
基本上,我只是改变了#34;代码"看起来像这样:
J1%nrstr(=)输入(J,anydtdtm。);下降j;重命名j1%nrstr(=)j; K1%nrstr(=)输入(K,anydtdtm。);下降k;重命名k1%nrstr(=)k; L1%nrstr(=)输入(1,anydtdtm。);下降l;重命名l1%nrstr(=)l;
我注意到如果我将宏更改为
data test3;
set test2;
statement=tranwrd(statement,"=",'%nrstr(=)');
call execute('%dummy('||strip(ds)||','||strip(statement)||')');
run;
然后这个解决方案没有用。它说"找到的位置参数比定义的更多"。有什么想法吗?
答案 4 :(得分:0)
所以宁愿将语句传递给宏,因为我假设你也生成了传递给宏的语句,我只传递变量名,原始和期望并使用数组。
%macro converter(var_in= , var_out=);
data want;
set data;
array have(*) &var_in;
array want(*) &var_out;
do i=1 to dim(have);
want(i)=input(have(i), anydtdtm.);
end;
drop &var_in;
run;
%mend;
%converter(var_in= j1 k1 l1, var_out= j k l);
编辑:基于注释的版本2.为了简化过程,我将变量重命名为temp1-temp {numvars},然后将它们重新编码为所需的变量。这已成功测试。
%macro converter(var_in= j k l);
%let n_vars = %sysfunc(countw(&var_in));
data want;
set data (rename = (%do i=1 %to &n_vars;
%scan(&var_in, &i)=temp&i
%end;));
array have(*) temp1-temp&n_vars.;
array want(*) &var_in;
do i=1 to dim(have);
want(i)=input(have(i), anydtdtm.);
end;
drop temp1-temp&n_vars;
run;
%mend;
%converter(var_in= j k l);