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

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

作者: 生物统计与SAS研究员 | 来源:发表于2021-05-25 12:34 被阅读0次

    上一篇是关于%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次,是因为在第一次执行转义之后,所有的%就都被替换成其他字符了,因此也就不会又后面的转义了。

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/mtbqsltx.html