如何防止CATx函数评估表达式

时间:2015-10-13 18:24:12

标签: sas sas-macro

使用%sysfunc调用CATT()函数时,有没有办法阻止它评估表达式?

例如给出代码:

%let date=10-13-2015;
%put %sysfunc(catt(The date Is:,&date));

我希望它返回:

The date Is:10-13-2015

因为10-13-2015只是一个文本字符串。但是,CATT()将连字符视为减法符号,并将其作为数值表达式进行计算,返回:

The date Is:-2018

我尝试过宏引用,但没有改变任何东西,我想因为我需要以某种方式隐藏来自CATT()的值。似乎CATT的任何参数看起来像一个表达式,它将被视为这样。

另一个例子:

%let value=2 and 3;
%put %sysfunc(catt(The value Is:,&value));
The value Is:1

4 个答案:

答案 0 :(得分:1)

如果您可以这样做,只需删除逗号即可 - 无需将其分成单个参数(除非您使用的是catx()而不是catt()

%let date=10-13-2015;
%put %sysfunc(catt(The date Is: &date));

就个人而言,我认为最好的工作方式是将日期存储为SAS日期值,然后使用%sysfunc的第二个(可选)参数来应用格式。这提供了更好的灵活性。

%let date = %sysfunc(mdy(10,13,2015));
%put The date Is: %sysfunc(sum(&date),mmddyyd10.);

如果您坚持使用原始方法并且正在使用catx(),那么我不知道该怎么做。我能得到的最接近的是插入一段文本,因此无法将其解释为表达式,然后使用tranwrd删除该文本。漂亮,丑陋,它留下了一个空间:

%let date=10-13-2015;
%let tmp=%sysfunc(catx(#, The date Is: , UNIQUE_STRING_TO_REMOVE&date ));
%let want=%sysfunc(tranwrd(&tmp, UNIQUE_STRING_TO_REMOVE, ));

%put &want;

给出:

The date Is:# 10-13-2015

我还尝试了宏引用的每个组合,并扫描整个SAS功能列表,看不到任何其他可行的选项。

答案 1 :(得分:1)

评估参数的%SYSFUNC()问题不仅限于CAT()系列函数。任何接受数值的函数都会导致SAS尝试评估提供的表达式。

这可能是一个有用的功能。例如:

%let start_dt=10OCT2012 ;
%put %sysfunc(putn("&start_dt"d +1,date9));

您不需要使用CAT()函数来处理宏变量。只需扩展彼此相邻的值,就可以“连接”。

%let date=10-13-2015;
%put The date Is:&date;

如果你想制作一个像CATX()函数一样的宏,那么这也不难做到。

%macro catx /parmbuff ;
%local dlm return i ;
%if %length(&syspbuff) > 2 %then %do;
  %let syspbuff = %qsubstr(&syspbuff,2,%length(&syspbuff)-2);
  %let dlm=%qscan(&syspbuff,1,%str(,),q);
  %let return=%qscan(&syspbuff,2,%str(,),q);
  %do i=3 %to %sysfunc(countw(&syspbuff,%str(,),q));
    %let return=&return.&dlm.%qscan(&syspbuff,&i,%str(,),q);
  %end;
%end;
&return.
%mend catx;

%put %catx(|,a,b,c);
a|b|c
%put "%catx(",",a,b,c,d)";
"a","b","c","d"

答案 2 :(得分:1)

不幸的是,我没有看到一个简单的方法。我确实看到你可以在理论上通过FCMP函数传递它,但是因为FCMP不允许真正的变量参数,这也不是理想的,但是......

proc fcmp outlib=work.funcs.funcs;
  function catme(delim $, in_string $) $;
    length _result $1024;
    length _new_delim $1;
    _new_delim = scan(in_string,1,delim);
    do _i = 1 to countc(in_string,delim);
      _result = catx(_new_delim, _result, scan(in_string,_i+1,delim));
    end;
    return(_result);
  endfunc;
quit;

options cmplib=work.funcs;

%let date=10-13-2015;
%put %sysfunc(catme(|,:|The date Is| &date.));

或者在参数中添加引号,然后在CATx之后删除它们。

%sysfunc(dequote(%sysfunc(catt(.... ,"&date."))))

一切都很乱。

答案 3 :(得分:0)

没有dosubl

稍微不那么疯狂的函数式宏
%macro catx() /parmbuff;
%local rc dlm i params OUTSTR QWORD outstr;
%let SYSPBUFF = %qsubstr(&SYSPBUFF,2,%length(&SYSPBUFF)-2);
%let dlm = %qscan(&SYSPBUFF,1,%str(,));
%let params = %qsubstr(&SYSPBUFF,%index(&SYSPBUFF,%str(,))+1);

%let i = 1;
%let QWORD = %scan(&PARAMS,&i,%str(,));
%let OUTSTR = &QWORD;
%do %while(&QWORD ne);
    %let i = %eval(&i + 1);
    %let QWORD = %scan(&PARAMS,&i,%str(,));
    %if &QWORD ne %then %let OUTSTR = &OUTSTR.&DLM.&QWORD;
%end;

%unquote(&OUTSTR)
%mend catx;

%put %catx(%str( ),abc,10 - 1 + 2,def);

更疯狂但显然工作的选项 - 使用%sysfunc(dosubl(...))和许多宏逻辑来创建一个函数式宏,它以与%sysfunc(catx(...))相同的方式获取输入,但强制catx​​处理所有输入作为文本引用并在数据步骤中调用它。

%macro catxt() /parmbuff;
%local rc dlm i params QPARAMS QWORD outstr;
%let SYSPBUFF = %qsubstr(&SYSPBUFF,2,%length(&SYSPBUFF)-2);
%let dlm = %qscan(&SYSPBUFF,1,%str(,));
%let params = %qsubstr(&SYSPBUFF,%index(&SYSPBUFF,%str(,))+1);

%let i = 1;
%let QWORD = "%scan(&PARAMS,&i,%str(,))";
%let QPARAMS = &QWORD;
%do %while(&QWORD ne "");
    %let i = %eval(&i + 1);
    %let QWORD = "%scan(&PARAMS,&i,%str(,))";
    %if &QWORD ne "" %then %let QPARAMS = &QPARAMS,&QWORD;
%end;

%let rc = %sysfunc(dosubl(%str(
    data _null_;
        call symput("OUTSTR",catx("&dlm",%unquote(&QPARAMS)));
    run;
)));

&OUTSTR
%mend catxt;

%put %catxt(%str( ),abc,10 - 1 + 2,def);

虽然这使用数据步骤来执行catx,但dosubl允许在通常使用%sysfunc(catx(...))的任何地方运行整个事件。