如何防止 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(...))
的任何地方成为 运行。
使用 %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(...))
的任何地方成为 运行。