[英]Passing an equals sign to a macro in SAS
我試圖在數據步驟中生成代碼,然后將代碼傳遞到宏中,然后運行該代碼。 我知道這有點round回,但我想不出更好的解決方案,因為我的代碼內容基於數據集中的內容。
在我的數據集“ test2”中,我只有一個觀察到變量“ statement”,它等於
j1 =輸入(j,anydtdtm。); 放下j; 重命名j1 = j; k1 = input(k,anydtdtm。); 下降k; 重命名k1 = k; l1 = input(l,anydtdtm。); 降l; 重命名l1 = l;
我有一個基本上是一個宏
%macro dummy(ds,statements);
data &ds.2;
set &ds.;
&statements.
run;
%mend;
然后我使用調用執行以下內容:
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;
但這沒用。 有人有想法么?
謝謝你的幫助!!
首先,如果使用命名參數,這不是問題。
%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運行該調用execute時,它將傳遞該%str
或%nrstr
並引用正在發送的值。
當您在其他地方擁有它時:
execstr = cats('%dummy(ds=class,statements=',%nrstr(all_statements),';)');
被保護/引用的不是all_statements
內的文本,而是實際上的all_statements
字符(換句話說, 變量名 )。 這實際上對您沒有多大作用。
傳遞等號很容易,只需在調用中使用命名參數即可。
%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()
函數將語句括在引號中。
options mprint;
data _null_;
set have ;
call execute(cats('%nrstr(%dummy)(',ds,',',quote(trim(statements)),')'));
run;
這是日志。
1 + %dummy(x,"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;")
MPRINT(DUMMY): data x2;
MPRINT(DUMMY): set x;
MPRINT(DUMMY): j1=input(j,anydtdtm.);
MPRINT(DUMMY): drop j;
MPRINT(DUMMY): rename j1=j;
MPRINT(DUMMY): k1=input(k,anydtdtm.);
MPRINT(DUMMY): drop k;
MPRINT(DUMMY): rename k1=k;
MPRINT(DUMMY): l1=input(l,anydtdtm.);
MPRINT(DUMMY): drop l;
MPRINT(DUMMY): rename l1=l;
MPRINT(DUMMY): run;
在以下情況中,可能更容易在文件中生成代碼,然后使用%include語句提交代碼:
filename tempsas temp;
data test3;
set test2;
file tempsas;
put
'data ' ds +(-1) '2;' /
' set ' ds ';' /
' ' statements /
'run;'
;
run;
然后,您可以通過查看文件(在編輯窗口中使用“ include tempsas”命令)開始,提交一個數據步驟以查看一切是否正常,並在確定一切正常后,將
%include tempsas;
在您的原始代碼中。
在這里閱讀了注釋(感謝您的幫助!)之后,我想出了一個不同的解決方案(盡管更改宏以接受命名參數也可以):
data test3;
set test2;
statement=tranwrd(statement,"=",'%nrstr(=)');
call execute('%dummy('||strip(ds)||','||strip(statement)||')');
run;
基本上,我只是將“代碼”更改為如下形式:
j1%nrstr(=)input(j,anydtdtm。); 放下j; 重命名j1%nrstr(=)j; k1%nrstr(=)input(k,anydtdtm。); 下降k; 重命名k1%nrstr(=)k; l1%nrstr(=)input(l,anydtdtm。); 降l; 重命名l1%nrstr(=)l;
我注意到如果我將宏更改為
%macro dummy(ds=,statements=);
data &ds.2;
set &ds.;
&statements.
run;
%mend;
然后這個解決方案不起作用。 它說“找到的位置參數比定義的更多”。 有什么想法嗎?
因此,寧願將語句傳遞給宏,因為我假設您也正在生成要傳遞給宏的語句,所以我只會傳遞原始和所需的變量名,並使用數組。
%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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.