P*****i 发帖数: 63 | 1 看到这一块时感觉好烦呀,困惑有如当年刚见识指针的指针一般。
好吧,我能理解,每个处理普通字符的宏函数都有一个对应处理特殊字符的宏函数,有如%UPCASE之于%QUPCASE。后者的作用就是能无视&和%这两个特殊解析宏的字符。
但当书上这个例子一抛出,楼主便陷入了懵逼中。
%let a=begin;
%let b=%nrstr(&a);
%put UPCASE produces: %upcase(&b);
%put QUPCASE produces: %qupcase(&b);
嵌套的宏解析...
一点点来捋吧。首先,带%的func一定是跟宏相关,要能解析带&后面的字符串参数,将宏替换为相应的值,再以对应的普通函数处理。所以,%UPCASE 就是专门处理宏为参数的UPCASE函数。
在这个例子里,宏a对应的值解析为begin, 宏b的赋值因为无视&的存在,所以解析为&a。
那么,%UPCASE(&b)上来先对&b做解析,得到&a, 然后
下一步呢?
是函数表达式变成了UPCASE(&a), 还是UPCASE(begin)?
但无论是哪个分支,都不大像能得出结果小写的begin啊。
后面QUPCASE我大概能蒙对,因为不再对&a做进一步解析,所以会得出&A.
如果这里没搞懂,后头整个人都会不好了。因为下面还有一大坨%SUBSTR, %SCAN, %INDEX以及对应的特殊字符分身,可以想象这里头能埋伏多少变形的海量题目来搞你,简直生无可恋。 | m******r 发帖数: 1033 | 2 这东西吧 确实烦人。 可也没什么大不了的。 无非就是上机自己试一试罢了,对着结
果怎么都能解释得通。 你也可以开那三个常用的option. 什么mprint symbolgen之类
,对着log一点点抠。 这就是sas的牛逼之处, 大不了对着log死磕,所有的问题都能
解决。 就凭这一点,一年给sas交一万块钱, 值。 | P*****i 发帖数: 63 | 3 嗯,是哒,我就是在机器上跑过了还是不懂。
SAS运行结果如下:
199 options symbolgen;
200 %let a=begin;
201 %let b=%nrstr(&a);
202 %put UPCASE produces: %upcase(&b);
SYMBOLGEN: Macro variable B resolves to &a
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been
unquoted for printing.
SYMBOLGEN: Macro variable A resolves to begin
UPCASE produces: begin
~~~~~~~~~~~~~~~~~~~~~~~
这里为什么UPCASE不进一步执行替换大写的操作?
203 %put QUPCASE produces: %qupcase(&b);
SYMBOLGEN: Macro variable B resolves to &a
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been
unquoted for printing.
QUPCASE produces: &A
顺带说一下,如果把代码从参数&b改为&a,去掉一层嵌套解析后,结果是这样的:
5 %let a=begin;
6 %let b=%nrstr(&a);
7 %put UPCASE produces: %upcase(&a);
UPCASE produces: BEGIN
8 %put QUPCASE produces: %qupcase(&a);
QUPCASE produces: BEGIN
这个又反过来了,我不大理解后面这个结果,前头等于是先解析了宏a, 变为
UPCASE(begin)=BEGIN, 没问题;
但%QUPCASE(&a)不是该直接无视&, 按照普通字符串'&a'传给upcase作参数得到&A么?
【在 m******r 的大作中提到】 : 这东西吧 确实烦人。 可也没什么大不了的。 无非就是上机自己试一试罢了,对着结 : 果怎么都能解释得通。 你也可以开那三个常用的option. 什么mprint symbolgen之类 : ,对着log一点点抠。 这就是sas的牛逼之处, 大不了对着log死磕,所有的问题都能 : 解决。 就凭这一点,一年给sas交一万块钱, 值。
| P*****i 发帖数: 63 | 4 下一个例子:
%let a=one;
%let b=two;
%let c=%nrstr(&a &b)
%put C: &c
%put With SUBSTR: %substr(&c,1,2);
%put With QSUBSTR: %qsubstr(&c,1,2);
这里书上的道理我是懂的,第一个,先解析为
%substr(&a &b,1,2)
看上去要得到书上的结果one, 这里%substr是直接对字符串&a &b做一次解析取子字符串,所以从第一个字符开始读两位,得到&a, 这时候substr执行完,然后结果&a解析为one.
这里让人困惑的是,程序解析的顺序到底是怎么来的,为什么不是按substr(one two, 1,2)来?那就乱套了。
第二个,也是先得到qsubstr(&a &b, 1, 2), 然后取子字符&a出来,无视&停止下一步解析,得到结果&a.
好吧,道理我勉强懂,然而,机器上这段没能通过编译。。。
232 %put With SUBSTR: %substr(&c,1,2);
ERROR: Open code statement recursion detected.
233 %put With QSUBSTR: %qsubstr(&c,1,2);
ERROR: Open code statement recursion detected. | m******r 发帖数: 1033 | 5 我跟你说了,大可不必如此纠结。 宏这个东西虽然复杂,实际工作中只要简单试一试
,都能试出来。为什么我说不必纠结呢? 宏这个东西,在open code下跑和在 macro里
面跑,结果会不一样;还分编译阶段和执行阶段。 总之绕弯的地方很多 实际应用却很
少;宏编译器自己里面有时会解析好几次,有时解析一次 然后扔给数据步。 你把它当
个黑盒子用就行,好比一辆车能把你从A带到B, 你没必要非把它拆了 除非你以修车为
生。
你的代码我看了,头一个例子没什么解释不通的。 log不是已经有了一次大写的值嘛?
至于为什么最终结果没有大写,我觉着无所谓 (人家就解析一次 为什么要来来回回
在里面解析?)。 另外你知道sas对大小写不敏感吧 ?
你第二个例子,如果是你自己上机实验的,那挺好。 不通过就不通过,你哪里随便改
改,就能通过了,达到你的目的就行。 如果书上写能通过,你的却不能通过,那可能
要研究一下。 | P*****i 发帖数: 63 | 6 感谢解答。
有空我可能还是搞清楚一下心里比较踏实,因为字符函数的应用场合是case sensitive
的,比如拿来做字符比较判断。 | P*****i 发帖数: 63 | 7 还有,为啥还有%let a = &a这种用法?这不相当于把指针内容直接赋值给指针对象本
身了么?这也行? | m******r 发帖数: 1033 | 8 不知道你从哪里看的把宏和指针联系起来, 谁教你的啊?
sas 宏有一张宏变量的表。 宏运行的时候,解析其实就是查表
有这个概念 程序怎么写都无所谓。 | P*****i 发帖数: 63 | 9 今天又想了下,结果取决于函数执行的时序。
一步步细分来看:
%let b=%nrstr(&a);
对于%upcase(&b)的执行时序:
1. 因为&b含有macro trigger,所以先解析到&a
2. 这里谁先谁后很重要,在input stack里接下来一步如果是%upcase接管,
那么%upcase执行后结果变成了&A
3. 下一步,因为upcase已经执行过了,针对&A, word scanner不会再重复执行一遍转换大写的操作,结果只由macro trigger再行解析到begin, 这时候解析&a和&A没区别,都指向begin.
这样解释的关键是在时序上要按照先解析第一步, 然后马上执行upcase操作,之后再解析upcase执行完之后的结果三步来才说的通.
换成QUPCASE执行.
在第二步里同样是换成了&A, 但是因为mask掉了&,结果停留在&A不再做进一步解析.
同样道理来看:
%let a=one;
%let b=two;
%let c=%nrstr(&a &b);
310 The %INDEX Function Chapter 9
%put C: &c
%put With SUBSTR: %substr(&c,1,2);
1. C会被解析为&a &b (中间带空格)
1.1 但此时没有下一步解析! 这时候由函数substr接管!
2. substr马上接着执行, 取到子字符集为&a为函数执行结果
3. 因为结果里含macro trigger, SAS进一步解析结果为one.
而对于qsubstr,区别是取到子集&a后因为mask掉&, 所以结果停留在&a.
举一反三看%SCAN和%QSCAN:
%let a=one;
%let b=two;
%let c=%nrstr(&a*&b);
%put C: &c;
%put With SCAN: %scan(&c,1,*);
%put With QSCAN: %qscan(&c,1,*);
1. C先被解析为&a*&b (nrstr无视特殊字符,不trigger one和two的解析)
2. scan对&a*&b做扫描操作, 碰到分隔符*的第一个词的结果就是&a
3. 因为含macro trigger, SAS进一步解析&a为one
对于QSCAN, 在第二步扫描得到&a后mask掉&不触发下一步解析,最后结果为&a.
【在 P*****i 的大作中提到】 : 看到这一块时感觉好烦呀,困惑有如当年刚见识指针的指针一般。 : 好吧,我能理解,每个处理普通字符的宏函数都有一个对应处理特殊字符的宏函数,有如%UPCASE之于%QUPCASE。后者的作用就是能无视&和%这两个特殊解析宏的字符。 : 但当书上这个例子一抛出,楼主便陷入了懵逼中。 : %let a=begin; : %let b=%nrstr(&a); : %put UPCASE produces: %upcase(&b); : %put QUPCASE produces: %qupcase(&b); : 嵌套的宏解析... : 一点点来捋吧。首先,带%的func一定是跟宏相关,要能解析带&后面的字符串参数,将宏替换为相应的值,再以对应的普通函数处理。所以,%UPCASE 就是专门处理宏为参数的UPCASE函数。 : 在这个例子里,宏a对应的值解析为begin, 宏b的赋值因为无视&的存在,所以解析为&a。
| S*********e 发帖数: 21 | 10 天哪楼主我已经要看晕了…顺便问一下,你看prep guide的时候都会这样脑海里转换成
中文看吗? | m******r 发帖数: 1033 | 11 lz精神可嘉. 其实任何一种语言都有处理特殊字符的模块,不知道为什么sas特别加强
了这个功能。我想自有它的道理 我等无需杞人忧天 | S******y 发帖数: 1123 | 12 用Python处理字符 非常简明
-StatsGuy
http://www.statsguy.net/
【在 m******r 的大作中提到】 : lz精神可嘉. 其实任何一种语言都有处理特殊字符的模块,不知道为什么sas特别加强 : 了这个功能。我想自有它的道理 我等无需杞人忧天
|
|