SAS-Macro 中的那些语句(四)

2019-10-20 18:44:58 浏览数 (1)

这还是继续前面的基础说,今天来说一说宏中数值运算、几个常见函数等...

宏数值运算

大家都知道SAS数据集中的变量是分数值型、字符型的。那么SAS的宏变量是否分数值型变量和字符型变量呢?是不分的,那么宏变量的计算是直接算么?当然是不是的,宏变量的计算是有俩个关键词%eval(只能进行整数的运算),%sysevalf(可进行整数运算与小数运算)....

代码语言:javascript复制
data _null_;
  call symput('mvar1','1.213');
  call symput('mvar2','2.1');
  call symput('mvar3','99999');
  call symput('mvar4','333');
  call symput('mvar5','21');
run;

  /*********************************

    %eval只支持整数的运算

  **********************************/
  %put  NOTE:'%eval(&mvar5.-&mvar2.)=' %eval(&mvar5.-&mvar2.);/*会有ERROR*/
  %put  NOTE:'%eval(&mvar5.-&mvar2.)=' %eval(&mvar4.-&mvar5.);
  %put  NOTE:'%eval(&mvar5.*&mvar4.)=' %eval(&mvar5.*&mvar4.);
  %put  NOTE:'%eval(&mvar5.*&mvar2.)=' %eval(&mvar5.*&mvar2.);/*会有ERROR*/
  /*********************************

    %SYSEVALF支持浮点运行

  **********************************/
  %put  NOTE:'%SYSEVALF(&mvar5.-&mvar2.)=' %SYSEVALF(&mvar5.-&mvar2.);
  %put  NOTE:'%SYSEVALF(&mvar4.-&mvar5.)=' %SYSEVALF(&mvar4.-&mvar5.);
  %put  NOTE:'%SYSEVALF(&mvar5.*&mvar4.)=' %SYSEVALF(&mvar5.*&mvar4.);
  %put  NOTE:'%SYSEVALF(&mvar5.*&mvar2.)=' %SYSEVALF(&mvar5.*&mvar2.);

%eval进行运算的宏变量有小数点是会有Error的...那么来看看日志。

%sysfunc

前几天小编推送了一大堆SAS里面的基础函数,那么那些函数在宏是否可以用呢?可以用的,不过需要用一个东西包裹起来...是什么东西呢?那就是%sysfunc(),很简单的...那么来看看一个例子,更加直接的理解函数...

代码语言:javascript复制
data _null_;
  call symput('mvar1','1.213');
  call symput('mvar2','2.1');
  call symput('mvar3','99999');
  call symput('mvar4','333');
  call symput('mvar5','21');
run;
  /*********************************

    宏中用SAS普通的函数(%sysfunc()包裹起来,中间放SAS中的普通函数)

  **********************************/
  %put  NOTE:'%sysfunc(Max(&mvar5.,&mvar1,&mvar2,&mvar3,&mvar4))=' %sysfunc(Max(&mvar5.,&mvar1,&mvar2,&mvar3,&mvar4));
  %put  NOTE:'%sysfunc(min(&mvar5.,&mvar1,&mvar2,&mvar3,&mvar4))=' %sysfunc(min(&mvar5.,&mvar1,&mvar2,&mvar3,&mvar4));

例子举的是Max与Min函数...除了加了%sysfunc包裹起来,其他的和都没区别和变化....

宏中的函数

那么宏中的函数必须用%sysfunc()包裹起来么,不是的。SAS还将几个常用的函数直接变成了宏函数,都有那几个常用的函数呢?%length,%index,%substr,%scan,%upcase,这几个常见的函数...除了加了一个%,其他的都没变化...如果记性好的朋友,并且看过上一篇推送的朋友,注意发现细节的朋友...好像没有这样的朋友

应该会注意到昨天%do...%while的例子中小编用了一个%qscan函数...为啥%scan多了一个q呢?还是先看看例子...

代码语言:javascript复制
%macro test;
%let dslist=ds1sheetname1contents1title1|ds2sheetname2contents2title2|ds3sheetname3contents3title3;
%let i=1;
%do %while(%qscan(&dslist,&i,|)^=%str());
 %let list&i=%qscan(&dslist,&i,|);
 %let dsn&i=%qscan(&&list&i.,1,);
 %let sht&i=%qscan(&&list&i.,2,);
 %let cnt&i=%qscan(&&list&i.,3,);
 %let tle&i=%qscan(&&list&i.,4,);
 %put NOTE:循环次数(&i.) &&dsn&i &&sht&i &&cnt&i &&tle&i;
 %let i=%eval(&i 1);
%end;    
 %let _loop=%eval(&i-1);
%mend;
%test

看吧,是不是用的%qscan,那么他们的区别的啥呢,在SAS中有一些特殊字符,如:&,%...等,这个能干嘛呢?能屏蔽掉一些特殊字符....可能这里并不能很好的体现那么小编在网上找了2个简化的例子...

代码语言:javascript复制
%macro test();
%let mvar1=%nrstr(四海/翻腾/云水怒&九州/震荡/风雷激);
%let mvar2=&mvar1.;
%let i=1;
   %do %while ( %qscan(&mvar2.,&i.,"/") ne %str( )  );
       %let msg=%qscan(&mvar2.,&i.,"/");
       %put NOTE: &msg.;
       %let i=%eval(&i. 1);
   %end;

%let i=1;
   %do %while ( %scan(&mvar2.,&i.,"/") ne %str( )  );
       %let msg=%scan(&mvar2.,&i.,"/");
       %put NOTE: &msg.;
       %let i=%eval(&i. 1);
   %end;

%mend;
%test;

小编将这个%qscan,与%scan放到一起做比对,当执行到%scan某处的时候,会因为错误造成宏的终止....为啥会终止呢,那是因为里面存在特殊字符&。%qscan相对来说较常见...其他的还有几个大概都一样吧,因为小编也没用过,只用过%qscan..还是来看一下日志...

宏变量的解析

其实宏变量的解析应该放到很前面说的,不过宏变量的解析也是太简单了,例子看俩个就能自己领悟的...所以也没打算说。。不过为了引出另外的一个关键词,还是浅谈一下...毕竟,一般公司在笔试应届毕业生SAS programmer、或者应届毕业生转正考试的时候经常会遇到宏变量解析的笔试题...那么久来看看几个简单的例子

代码语言:javascript复制
%let i=1;
%let m=2;
%let m1=你好;
%let m12=我好;

/*单个解析:用宏变量在日志打印出 1*/
%put NOTE:&I;
%put NOTE:%superq(I);
/*单个解析:用宏变量在日志打印出 12*/
%put NOTE:&I&M;
%put NOTE:%superq(I)%superq(M);
/*双重解析:用宏变量在日志打印出 你好*/
%put NOTE:&&M&i;
%put NOTE:%superq(m&i);
/*多重解析:用宏变量在日志打印出 我好*/
%put NOTE:&&M&i&m;
%put NOTE:%superq(m&i&m);

这儿的日志就不贴了...

%superq() 解析括号内作为一个整体的宏变量,

这个关键词可以起到解析宏变量的作用,当然此处还没有完全的体现出%superq在SAS中的真正的应用....

代码语言:javascript复制
data _null_; 
  call symput('msg', '你真美!'); 
  call symput('macvar1', 'msg&msg'); 
run; 
%put NOTE: &macvar1.;
%put NOTE: %superq(macvar1);

有时候,我们不需要解析macvar1 中的&符号..此时就可以用%superq进行操作...

现在又要说到上一篇的一个例子,%return中的一个,那么现在再来看一个下这个例子...

代码语言:javascript复制
%macro  test(inds);

%if %sysfunc(exist(%superq(inds))) eq 0  %then  %do;
%put NOTE:你输出数据集(%superq(inds))不存在...请核查!;
%return;
%end;

%put NOTE:你输出数据集(%superq(inds))不存在,该宏继续执行...;
%mend;


%test(a);
%test(SASHELP.CLASS);

%put NOTE:即将见证奇迹的时刻了...;
%let ss=SASHELP.CLASS;
%test(&ss.);

猜一猜即将见证奇迹后面的代码执行,会有什么效果?据说%superq作用在执行期,SAS程序的执行是先编译在执行...猜完了,在来看看日志...

奇怪不奇怪?为啥第一条横向的那个地方没有解析出SASHELP.CLASS数据集,而第二条横向却解析出了数据,到底是啥?

我也不太清楚...小编现在境界不够!还理解不了这些,那么所以说:%superq要用在合适的场合~程序语言都要慎用...

Quoting

上面,已经遇到了一个小编解释不出来的东西,那么接下还有...

%str()/%nrstr()/%bquote/%nrbquote...这些都是干嘛的呢,%str()与%nrstr()可以在小编的历史推送中的例子时长出现,这个俩个是作用在编译期间,可以屏蔽一些特殊符号,%bquote/%nrbquote作用在执行期间,同样可以屏蔽一些特殊符号,所以前面俩个和后面俩个区别在于作用的期间....那么带有nr与不带有nr之间又有什么区别呢?NR=NOT Resolved,带有NR比不带NR多屏蔽俩个特殊字符(&、%)...其他就没啥区别了...

关于这几个小编见识不够...所以自己就不写自己的理解了...小编还要请教各位大神一个问题....(先给大家分享几个去处,可以看一看别人分享的这部分的内容:第一个去出:SAS中文论坛(微信公众号)-精品推荐-SAS百家讲坛-言论里面,第二个去出:知乎(SAS IN PHARMA)-一个叫木鱼的大神发的帖子...里面的帖子好像全是这个大神发的...非常不错的帖子...)那么在来看看我的问题..

代码语言:javascript复制
data _null_;
  call symput('mac', '%str(&sss)'); 
  call symput('mac1', '%nrstr(&sss)'); 
  call symput('mac2', '%bquote(&sss)'); 
  call symput('mac3', '%nrbquote(&sss)'); 
run;
%put NOTE:&mac.;
%put NOTE:&mac1.;
%put NOTE:&mac2.;
%put NOTE:&mac3.;

这里我没有定义&sss宏变量,我的问题是为啥日志的警告是1,0,2,1...我这这样的瞎想的,想的我自己还以为是真的(肯定不是真的)....

代码语言:javascript复制
/*

1次警告原因:在 %put NOTE:&mac.;进行编译的时候,发现&mac存在,便开始进行执行,在执行过程中,先将&mac解析成%str(&sss)
此时,由于%str()作用在编译期间,且不对&符号进行屏蔽,此时保出了一个警告,便将&sss当做一个字符串,进行了执行...
*/
%put NOTE:&mac.;
/*
0次警告原因:在 %put NOTE:&mac1.;进行编译的时候,发现&mac存在,便开始进行执行,在执行过程中,先将&mac解析成%nrstr(&sss)
此时,由于%nrstr()作用在编译期间,且对&符号进行屏蔽,便将&sss当做一个字符串,进行了执行...
*/

%put NOTE:&mac1.;
/*
2次警告原因:在 %put NOTE:&mac2.;进行编译的时候,发现&mac存在,便开始进行执行,在执行过程中,先将&mac解析成%bquote(&sss)
此时,由于%bquote()作用在执行期间,且不对&符号进行屏蔽,发现&sss不存在便报出了一次警告,由于%bquote()的存在,造成了未知因素的干扰,
并未将&sss作为字符串,进行了执行,在执行时又发现了&sss不存在...
*/

%put NOTE:&mac2.;
/*
1次警告原因:在 %put NOTE:&mac3.;进行编译的时候,发现&mac存在,便开始进行执行,在执行过程中,先将&mac解析成%nrbquote(&sss)
此时,发现&sss不存在便报出了一次警告,进行了执行,但由于%nrbquote()作用在执行期间,且对&符号进行屏蔽,将&sss当做了字符串,所以只有编译那一次的警告...
*/
%put NOTE:&mac3.;

这个问题是怎么来的呢?这个问题是另外的一个问题的简化版,那么来看下另外的一个问题....

这里的ERROR:2,3,1应该怎么理解呢....就是上面的那个问题的简化版...

0 人点赞