上一篇是關(guān)于%str和%nrstr兩個(gè)函數(shù)的SAS 程序冷知識(shí)——一個(gè)關(guān)于%str和%nrstr的案例解讀 - 簡書
此處是上次的一個(gè)擴(kuò)展。同樣具有mask效果的quote一族是怎樣處理%的呢别凹?對(duì)于quote一族來說锣险,%當(dāng)然也具有兩個(gè)功能垄开,一個(gè)是宏的觸發(fā)符號(hào)答渔,一個(gè)是mask關(guān)鍵詞的功能养涮。
首先是bquote鸭丛,這個(gè)函數(shù)的作用是mask所有特殊符號(hào)后频,所以在這函數(shù)里%不具備任何特殊符號(hào)的作用梳庆,所以不必用兩個(gè)%mask暖途。
有趣的是quote和nrquote,我們先看代碼:
%let s1=%%@2個(gè)百分號(hào);
%let s2=%%%%@4個(gè)百分號(hào);
%let s3=%%%%%%%%@8個(gè)百分號(hào);
%let s4=%%%%%%%%%%%%%%%%@16個(gè)百分號(hào);
%macro a(quote=,nrquote=);
%put &=quote.;
%put &=nrquote.;
%mend;
%a(quote=%quote(&s1.),nrquote=%nrquote(&s1.));
%a(quote=%quote(&s2.),nrquote=%nrquote(&s2.));
%a(quote=%quote(&s3.),nrquote=%nrquote(&s3.));
%a(quote=%quote(&s4.),nrquote=%nrquote(&s4.));
結(jié)果是:
QUOTE=%@2個(gè)百分號(hào)
NRQUOTE=%@2個(gè)百分號(hào)
QUOTE=%@4個(gè)百分號(hào)
NRQUOTE=%%@4個(gè)百分號(hào)
QUOTE=%%@8個(gè)百分號(hào)
NRQUOTE=%%%%@8個(gè)百分號(hào)
QUOTE=%%%%@16個(gè)百分號(hào)
NRQUOTE=%%%%%%%%@16個(gè)百分號(hào)
我們發(fā)現(xiàn)對(duì)于nrquote來說膏执,經(jīng)過該函數(shù)%的個(gè)數(shù)都減半了驻售。這個(gè)可以理解為:對(duì)于每對(duì)%而言,前一個(gè)%作為mask的符號(hào)更米,轉(zhuǎn)義了后一個(gè)%的特殊作用欺栗,然后前一個(gè)%完成使命消失,從而最后的個(gè)數(shù)是原來的一半征峦。
但是quote就有意思了迟几,在4個(gè)百分號(hào)的時(shí)候,結(jié)果依然是一個(gè)%眶痰,并且按照后面的規(guī)則看瘤旨,似乎quote在執(zhí)行了第一遍轉(zhuǎn)義之后,又進(jìn)行了一次轉(zhuǎn)義竖伯。
然后如果宏是這樣的:
%macro b(quote=,nrquote=);
%put quote=%quote("e.);
%put nrquote=%nrquote(&nrquote.);
%mend;
%b(quote=&s1.,nrquote=&s1.);
%b(quote=&s2.,nrquote=&s2.);
%b(quote=&s3.,nrquote=&s3.);
%b(quote=&s4.,nrquote=&s4.);
結(jié)果就完全不一樣存哲,變得正常了。
quote=% 2個(gè)百分號(hào)
nrquote=% 2個(gè)百分號(hào)
quote=%% 4個(gè)百分號(hào)
nrquote=%% 4個(gè)百分號(hào)
quote=%%%% 8個(gè)百分號(hào)
nrquote=%%%% 8個(gè)百分號(hào)
quote=%%%%%%%% 16個(gè)百分號(hào)
nrquote=%%%%%%%% 16個(gè)百分號(hào)
這個(gè)結(jié)果表明七婴,如果在宏變量賦值的時(shí)候祟偷,就帶著函數(shù)quote,那么當(dāng)使用的時(shí)候%會(huì)被作為轉(zhuǎn)義符執(zhí)行兩次打厘。為了驗(yàn)證這個(gè)結(jié)論我們?cè)僮鲆淮卧囼?yàn)修肠。
%let s1=%quote(%%@2個(gè)百分號(hào));
%let s2=%quote(%%%%@4個(gè)百分號(hào));
%let s3=%quote(%%%%%%%%@8個(gè)百分號(hào));
%let s4=%quote(%%%%%%%%%%%%%%%%@16個(gè)百分號(hào));
%put quote=&s1.;
%put quote=&s2.;
%put quote=&s3.;
%put quote=&s4.;
其結(jié)果為:
quote=%@2個(gè)百分號(hào)
quote=%@4個(gè)百分號(hào)
quote=%%@8個(gè)百分號(hào)
quote=%%%%@16個(gè)百分號(hào)
這個(gè)結(jié)果基本驗(yàn)證了我們的想法。那么為什么quote就會(huì)執(zhí)行兩次呢户盯?猜想原因是宏變量賦值的時(shí)候嵌施,是先執(zhí)行宏函數(shù),后賦值莽鸭。我們以%let s3=%quote(%%%%%%%%@8個(gè)百分號(hào));為例吗伤。當(dāng)賦值的時(shí)候,s3的值可以是%%%%@8個(gè)百分號(hào)硫眨。而當(dāng)我們使用語句:%put quote=&s3.;的時(shí)候足淆,由于解析宏變量中帶有%quote的功能,所以在解析后再次執(zhí)行轉(zhuǎn)義功能礁阁,從而產(chǎn)生的結(jié)果”%%@8個(gè)百分號(hào)”巧号。詳見:SAS 程序冷知識(shí)——一個(gè)關(guān)于%str和%nrstr的案例解讀(續(xù)) - 簡書?
那么為什么nrquote就不會(huì)有問題呢?我們通過試驗(yàn)看到了quote的運(yùn)行機(jī)制姥闭。quote和nrquote實(shí)際上本質(zhì)是在字符的兩端加上一個(gè)標(biāo)志符號(hào)丹鸿,這個(gè)符號(hào)往往我們無法直接通過put看到,但是如果用16進(jìn)制解析就能清楚看到棚品,我們顯示示例如下:
%let s1=%%%%%%%%@8個(gè)百分號(hào);
%let s2=%quote(%%%%%%%%@8個(gè)百分號(hào));
%let s3=%nrquote(%%%%%%%%@8個(gè)百分號(hào));
data _null_;
set sashelp.vmacro;
where name='S1';
S1=strip(value);
put S1= hex50.;
run;
data _null_;
set sashelp.vmacro;
where name='S2';
S2=strip(value);
put S2= hex50.;
run;
data _null_;
set sashelp.vmacro;
where name='S3';
S3=strip(value);
put S3= hex50.;
run;
執(zhí)行之后可以看到
S1中25有8個(gè)卜高,實(shí)際上是符號(hào)‘%’弥姻,到了S2中25變成了4個(gè),這說明quote已經(jīng)轉(zhuǎn)義掉了其中的4個(gè)掺涛。但是S2的前后各多了一個(gè)符號(hào),分別是03和08(20表示空格疼进,是長度不夠補(bǔ)位用的)薪缆。其他的位置,S1和S2完全一樣伞广,對(duì)應(yīng)的就是文字“@8個(gè)百分號(hào)”拣帽。
到了S3就更有趣了,和S2內(nèi)容一樣嚼锄,但區(qū)別在于開頭的符號(hào)從03變成了05减拭,然后百分號(hào)從25變成了10。
這樣我們就大致理解quote和nrquote的操作了区丑,當(dāng)使用這個(gè)函數(shù)的時(shí)候拧粪,首先函數(shù)會(huì)在字符兩端加上兩個(gè)符號(hào),結(jié)尾都是08沧侥,quote的開頭是03可霎,nrquote的開頭是05。一旦套上的是05宴杀,SAS會(huì)進(jìn)一步將原來的%和&轉(zhuǎn)換成其他符號(hào)癣朗,來達(dá)到mask宏觸發(fā)符號(hào)的目的。因此我們猜測執(zhí)行順序是這樣的:
1旺罢、解析quote或nrquote中的宏變量旷余。
2、兩端加上mask符號(hào)08扁达,03或05正卧。
3、有%的話進(jìn)行轉(zhuǎn)義罩驻,將+穗酥,-等符號(hào)進(jìn)行替換。
4惠遏、如果是nrquote砾跃,將%和&進(jìn)行符號(hào)替換。
5节吮、如果是quote抽高,檢查是否有%可以執(zhí)行。
而之所以nrquote不會(huì)執(zhí)行2次透绩,是因?yàn)樵诘谝淮螆?zhí)行轉(zhuǎn)義之后翘骂,所有的%就都被替換成其他字符了壁熄,因此也就不會(huì)又后面的轉(zhuǎn)義了。