将等号传递给SAS中的宏

时间:2016-08-04 00:44:20

标签: parameters macros sas call execute

我试图在数据步骤中生成代码,然后将代码传递给宏,然后运行代码。我知道,它有点迂回,但我无法想到更好的解决方案,因为我的代码内容基于数据集中的内容。

在我的数据集中," 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;

但它没有用。有人有什么想法吗?

感谢您的帮助!!

5 个答案:

答案 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);