SAS 程序冷知识——关于%quote系函数中%的转义问题

2021-05-25  本文已影响0人  生物统计与SAS研究员

上一篇是关于%str和%nrstr两个函数的SAS 程序冷知识——一个关于%str和%nrstr的案例解读 - 简书

此处是上次的一个扩展。同样具有mask效果的quote一族是怎样处理%的呢?对于quote一族来说,%当然也具有两个功能,一个是宏的触发符号,一个是mask关键词的功能。

首先是bquote,这个函数的作用是mask所有特殊符号,所以在这函数里%不具备任何特殊符号的作用,所以不必用两个%mask。

有趣的是quote和nrquote,我们先看代码:

%let s1=%%@2个百分号;

%let s2=%%%%@4个百分号;

%let s3=%%%%%%%%@8个百分号;

%let s4=%%%%%%%%%%%%%%%%@16个百分号;

%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.));

结果是:

QUOTE=%@2个百分号

NRQUOTE=%@2个百分号

QUOTE=%@4个百分号

NRQUOTE=%%@4个百分号

QUOTE=%%@8个百分号

NRQUOTE=%%%%@8个百分号

QUOTE=%%%%@16个百分号

NRQUOTE=%%%%%%%%@16个百分号

我们发现对于nrquote来说,经过该函数%的个数都减半了。这个可以理解为:对于每对%而言,前一个%作为mask的符号,转义了后一个%的特殊作用,然后前一个%完成使命消失,从而最后的个数是原来的一半。

但是quote就有意思了,在4个百分号的时候,结果依然是一个%,并且按照后面的规则看,似乎quote在执行了第一遍转义之后,又进行了一次转义。

然后如果宏是这样的:

%macro b(quote=,nrquote=);

%put quote=%quote(&quote.);

%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.);

结果就完全不一样,变得正常了。

quote=% 2个百分号

nrquote=% 2个百分号

quote=%% 4个百分号

nrquote=%% 4个百分号

quote=%%%% 8个百分号

nrquote=%%%% 8个百分号

quote=%%%%%%%% 16个百分号

nrquote=%%%%%%%% 16个百分号

这个结果表明,如果在宏变量赋值的时候,就带着函数quote,那么当使用的时候%会被作为转义符执行两次。为了验证这个结论我们再做一次试验。

%let s1=%quote(%%@2个百分号);

%let s2=%quote(%%%%@4个百分号);

%let s3=%quote(%%%%%%%%@8个百分号);

%let s4=%quote(%%%%%%%%%%%%%%%%@16个百分号);

%put quote=&s1.;

%put quote=&s2.;

%put quote=&s3.;

%put quote=&s4.;

其结果为:

quote=%@2个百分号

quote=%@4个百分号

quote=%%@8个百分号

quote=%%%%@16个百分号

这个结果基本验证了我们的想法。那么为什么quote就会执行两次呢?猜想原因是宏变量赋值的时候,是先执行宏函数,后赋值。我们以%let s3=%quote(%%%%%%%%@8个百分号);为例。当赋值的时候,s3的值可以%%%%@8个百分号。而当我们使用语句:%put quote=&s3.;的时候,由于解析宏变量中带有%quote的功能,所以在解析后再次执行转义功能,从而产生的结果”%%@8个百分号”。详见:SAS 程序冷知识——一个关于%str和%nrstr的案例解读(续) - 简书 

那么为什么nrquote就不会有问题呢?我们通过试验看到了quote的运行机制。quote和nrquote实际上本质是在字符的两端加上一个标志符号,这个符号往往我们无法直接通过put看到,但是如果用16进制解析就能清楚看到,我们显示示例如下:

%let s1=%%%%%%%%@8个百分号;

%let s2=%quote(%%%%%%%%@8个百分号);

%let s3=%nrquote(%%%%%%%%@8个百分号);

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;

执行之后可以看到

S1中25有8个,实际上是符号‘%’,到了S2中25变成了4个,这说明quote已经转义掉了其中的4个。但是S2的前后各多了一个符号,分别是03和08(20表示空格,是长度不够补位用的)。其他的位置,S1和S2完全一样,对应的就是文字“@8个百分号”。

到了S3就更有趣了,和S2内容一样,但区别在于开头的符号从03变成了05,然后百分号从25变成了10。

这样我们就大致理解quote和nrquote的操作了,当使用这个函数的时候,首先函数会在字符两端加上两个符号,结尾都是08,quote的开头是03,nrquote的开头是05。一旦套上的是05,SAS会进一步将原来的%和&转换成其他符号,来达到mask宏触发符号的目的。因此我们猜测执行顺序是这样的:

1、解析quote或nrquote中的宏变量。

2、两端加上mask符号08,03或05。

3、有%的话进行转义,将+,-等符号进行替换。

4、如果是nrquote,将%和&进行符号替换。

5、如果是quote,检查是否有%可以执行。

而之所以nrquote不会执行2次,是因为在第一次执行转义之后,所有的%就都被替换成其他字符了,因此也就不会又后面的转义了。

上一篇下一篇

猜你喜欢

热点阅读