在宏裡面,對於宏變量的解析是非常常見的一個語句,%scan也是比較常用的一個宏函數,尤其是在寫宏循環或者截取字符串時,通常都會用%scan函數來進行讀取。
%scan函數在SAS中不僅可以用於宏語句中,還可以用於普通的SAS語句中,包括data步和proc步。
下面簡單的說一下在這兩種情形下%scan的使用方法:
1.在宏語句中的使用:
這種用法是比較常見的,舉個簡單的例子,代碼如下所示:
%macro test;
%local var var1;
%let var = abc/def/gh;
%let var1 = %scan("&var.",1,/);
%put var1 = &var1.;
%mend;
%test;
最終我們得到的結果為:var1 = abc。
對於上述在宏語句中對宏變量結合宏函數進行解析,我們不需要加引號,直接解析就行。
那麼我們可以看看如果加了引號會出現什麼問題呢?
先將&var用雙引號」」括起來:
%let var1 = %scan("&var.",1,/);
最終日誌出現報錯:
出現這種報錯的原因是,當&var加上引雙號後,宏函數%scan需要截取的字符串就變成了」abc/def/gh」,那麼通過截取後,就變成了」abc這麼個字符串了,由於雙引號的不成雙,所以導致程序報錯,其實這種問題在宏裡面也會經常碰到,遇到這種特殊字符,為了避免它作為雙引號的作用,而把它看成一個普通字符,我們可以用%bquote函數來對它進行屏蔽。
通過如下代碼的方式:
%let var1 = %bquote(%scan("&var.",1,/));
只是最終我們得到的結果為:var1 = 「abc。
我們看到雙引號成單,並且在結果中現實顯示出來,但是日誌並沒有報錯。
接下來,我們將雙引號換成單引號,得到如下代碼:
%let var1 = %scan('&var.',1,/);
發現我們得到的結果為:var1 = 『&var.』。
這個很有意思哈,在宏變量解析裡面,如果對宏變量加了成雙的單引號,那麼宏變量就無法解析。那麼試想一下為了能夠讓他解析,同時單引號又不想去掉,怎麼辦呢?
還是%bquote函數,代碼如下:
%let var1 = %bquote(%scan('&var.',1,/));
這個時候發現我們得到的結果為:var1 = 『abc。
結果變成了帶成單的單引號了,究其原因還是在於宏函數%bquote屏蔽掉了單引號的作用,把它看成了普通的字符。關於宏函數對特殊字符的屏蔽我就不多說了,SASHELP中對於這類函數介紹的很詳細,大家可以去自行去看看。
另外囉嗦一下關於宏編譯和宏執行的區別,因為在宏函數對特殊字符的屏蔽也分為編譯時屏蔽和執行時屏蔽。
為了直白說明,給出下面兩行代碼吧:
%let var = %str(%"abc/def/gh);
%let var = %bquote("abc/def/gh);
第一行代碼中%str用於編譯時屏蔽,第二行代碼中%bquote用於執行時屏蔽,分別執行上述兩行代碼,發現第二行代碼會報錯,這就是編譯和執行的區別了。
當宏編譯時,引號發現不成雙,會報錯,而由於%str的屏蔽,程序不報錯,而%bquote由於只能在執行時屏蔽,而宏編譯時還沒執行,因此會報錯。
2.在普通SAS語句中的使用:
通常在普通SAS語句中,%scan用來解析宏變量獲取普通的SAS變量,例如:
%let var =abc/def/gh;
data _null_;
abc = 1;
var = %scan(&var.,1,/);
put var =;
run;
最終得到的結果為:var = 1。
這種語句下,切記不能加雙引號,一旦加了雙引號,程序就會報錯。
另外需要注意的是,不管是%scan還是scan函數,在對第三個參數進行設置時,需要記住參數是以字符作為間隔的,而不是以字符串作為間隔,例如:
%let var =abc/deg/fh*ge/;
data _null_;
fh = 1;
var = %scan(&var,3,*/);
put var =;
run;
終得到的結果為:var = 1。
從上述代碼知:當%scan截取第三個以」/」或者」*」為間隔的變量名fh,因此結果為1。