如何防止 CATx 函数计算表达式

How to prevent CATx functions from evaluating expression

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

例如给定代码:

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

我想 return:

The date Is:10-13-2015

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

The date Is:-2018

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

另一个例子:

%let value=2 and 3;
%put %sysfunc(catt(The value Is:,&value));
The value Is: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 删除该文本。漂亮,丑陋,它留下了 space:

%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 函数列表,没有看到任何其他可行的选项。

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

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

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

您不需要使用 CAT() 函数来处理宏变量。只需扩展彼此相邻的值,它们就是 "concatenated".

%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"

不幸的是,我没有找到解决这个问题的简单方法。我确实看到您理论上可以通过 FCMP 函数传递它,但由于 FCMP 不允许真正的变量参数,这也不理想,但是...

proc fcmp outlib=work.funcs.funcs;
  function catme(delim $, in_string $) $;
    length _result 24;
    length _new_delim ;
    _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."))))

乱七八糟。

没有 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(...)) 的任何地方成为 运行。