【SAS Says·扩展篇】撕数据! | 4. call PRXPOSN()
0. 前集回顾
1. 新的问题
2. 初识 PRXPOSN()
3. 问题解决
0. 前集回顾:
小王刚刚毕业,来到数说国际零售公司任数据分析师,产品部的妹子求助他,希望可以帮忙做这么一件事:下面是一份产品名单,有的行是产品的名字,有的行是产品的编号,现在只想将编号保留下来(即红色字体的部分),尤其是最后一行,这一行只要一部分。
(01)1872-8756 Body shop P1 Book B13 (05)9212-0098 PD(05)9206-4571 Shushuo phone (12) 6753-5513 None here PD(12)6434-4532 P&D Washing PC Pro4321S: (09) 1352-3154
小王写了一段代码,很快就搞定了:
data production; if _N_=1then pattern=PRXPARSE("/P?D?(dd) ?d{4}-d{4}/"); retain pattern; input name $char40.; length id $ 20; call PRXSUBSTR(pattern,name,start,length); if length GT 0thendo; id=substr(name,start,length); output; end; keep id; datalines; (01)1872-8756 Body shop P1 Book B13 (05)9212-0098 PD(05)9206-4571 Shushuophone (12)6753-5513 None here PD(12)6434-4532 P&DWashing PC Pro4321S:(09) 1352-3154 ; procprintnoobs; title'Production ID'; var id; run;
输出结果为:
这个问题真是圆满的解决了。
点击这里回顾:
- 提取文本数据,分析师小王初上手!
- 正则表达式的“阿赖耶识”
- 庖丁解牛切割数据!
1. 新的问题
不错,一个新的问题来了,
”括号里面的数字代表了产品的类别,能不能将它单独提出来?“
当然,你可以在目前的表的基础上,用excel处理,比如:
If 第一个字符是”(” then 提取后面两个数字
If 第一个字符是”P” then 提取后面第四、第五个数字
当然这也一点都不酷,而且如果名单的后面有其他变动,比如前面的PD被错拼成BD了、或者真有一个前缀是BD呢?
还是用正则表达式一次性搞定吧!这就要引出我们今天的主角——PRXSON!
2. 初识PRXPOSN()
这个语句要配合PAXMATCH(或其他PRX搜索函数)使用。需要三步:
① 在正则表达式中,用括号()将需要提取的一小部分括起来,我自己称之为“打包”,比如,在产品编号的例子中,我们需要打包括号里的两位数字,那么我们就在正则表达式中将这两个dd括起来:
“/P?D?((dd)) ?d{4}-d{4}/”
并放入pattern中:
Pattern=PRXPARSE(“/P?D?((dd)) ?d{4}-d{4}/”)
② 用PRXMATCH匹配这段正则表达式
PAXMATCH(pattern,name)
③ 用PRXPOSN函数得到产品编号(就是括号里,我们要提取的那个)的起始位置和长度。
CALLPRXPOSN(pattern, 1, start, length)
重点来了,PRXPOSN的格式为:
Call PRXPOSN(pattern-id, 区块编号, start, length)
这里pattern-id是正则表达式,区块编号就是正则表达式中,我们打包起来的。只打包一个,那么编号就是1,打包两个,那么可以选择1或者2。
然后,这个函数就把区块的起始位置和长度赋给了start和length。
④ 用substr()函数将区块抓下来
本例中,产品类型就是:
Category=Substr(name,start, length)
3. 问题解决
好了,现在来看一下本例中代码要怎么写:
data production; if _N_=1then pattern=PRXPARSE("/P?D?((dd)) ?d{4}-d{4}/"); retain pattern; input name $char40.; length id $ 20; call PRXSUBSTR(pattern,name,start,length); *下面的PRXPOSN必须要配合这个PRXMATCH使用; match =PRXMATCH(pattern, name); if length GT 0thendo; *得到产品ID; id=substr(name,start,length); id=compress(id," "); *得到ID中的产品类型(即括号里面的数字); call PRXPOSN(pattern, 1, start_1, length_1); category=substr(name, start_1, length_1); output; end; keep id category; datalines; (01)1872-8756 Body shop P1 Book B13 (05)9212-0098 PD(05)9206-4571 Shushuophone (12)6753-5513 None here PD(12)6434-4532 P&DWashing PC Pro4321S:(09) 1352-3154 ; procprintnoobs; title'Production ID'; var id category; run;
最后的结果为:
趁热,咱们再加一列吧,标识出哪些产品是过期的,即PD。
直接上代码,非常简单,大家自己研究研究吧:
data production; if _N_=1then pattern=PRXPARSE("/(P?D?)((dd)) ?d{4}-d{4}/"); retain pattern; input name $char40.; length id $ 20; call PRXSUBSTR(pattern,name,start,length); *下面的PRXPOSN必须要配合这个PRXMATCH使用; match =PRXMATCH(pattern, name); if length GT 0thendo; *得到产品整个ID; id=substr(name,start,length); id=compress(id," "); *得到ID中的产品类型(即括号里面的数字); call PRXPOSN(pattern, 2, start_2, length_2); category=substr(name, start_2, length_2); *得到ID中产品的过期信息; call PRXPOSN(pattern, 1, start_1, length_1); if length_1 gt 0then pd= substr(name, start_1, length_1); output; end; keep id category pd; datalines; (01)1872-8756 Body shop P1 Book B13 (05)9212-0098 PD(05)9206-4571 Shushuophone (12)6753-5513 None here PD(12)6434-4532 P&DWashing PC Pro4321S:(09) 1352-3154 ; procprintnoobs; title'Production ID'; run;
结果为: