提取文本数据,分析师小王初上手! 【SAS Says·扩展篇】正则表达式
SAS正则表达式可以让你把数小时辛苦而且易错的文本处理工作压缩在几分钟甚至几秒钟完成!...
文本分析很有用,数说君自己也玩过,炒鸡有意思,从论坛、网页上爬取网友的舆情数据,然后整理、统计、画图,就可以知道舆论的风暴是什么,可以知道网友最热议的话题、最想去的旅游景点、最喜欢的饮料等等,也可以从这些舆情数据中挖掘出两个话题之间的关联性等等。
扯的有点远,本系列【SAS Says · 扩展篇 · 正则表达式】介绍的是SAS里正则表达式的应用,对于一些杂乱无章的非结构化数据,正则表达式可是一个处理的利器!
它的使用其实很简单,一旦你弄懂它们,你就能把数小时辛苦而且易错的文本处理工作压缩在几分钟甚至几秒钟完成!
【SAS Says·扩展篇】分析师小王初上手! | 1. PRXMATCH ()
本集目录:
0. 小王初上手
1. 初始PRXMATCH()
2. metacharater
2.1 什么是metacharater?
2.2 例子
2.3 metacharater总结
3. 问题解决
3.1 问题重述
3.2 问题理解
3.3 解决代码
数说工作室原创,转载只需放置数说工作室二维码,并注明来源。
数据库中有一份长长的产品名单,名单中有的是产品的名字,有的是产品的编号,产品部的妹子只想要产品的编号的那些行(下图红色字体的),以做更深一步的分析。
红色字体的编号似乎没有什么容易把握的规律:占位符不一样、也不全都是数字、有的行的括号后面还有空格等等,这怎么提取呢?(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
......(未显示完)
你是否在绞尽脑汁的想各种字符串函数、想各种匹配的规则,比如用substr(name,1,1) in (“(“,”P”),这个不行,因为有的非编号的行开头也可能是P、或者PD等......
可以歇歇了,因为小王只用了1分钟不到,就把代码写好并提取出来了,我们先来看下他的代码:
结果为:这代码是个什么玩意儿啊?a=PRXMATCH("/(dd) ?d{4}-d{4}/", name);
if a GT 0 then output;
这些看起来像乱码的东西就是正则表达式和元字符,下面,我们就从一个函数PRXMATCH()来入手,学习一下如何使用正则表达式。
举个例子:
结果为:data _null_;
STRING="I love Shushuo jun";
a=PRXMATCH("/Shu/",STRING);
file print;
put a=;
run;
Shu在I love Shushuo jun中的位置是8。
我们来解释一下“/Shu/”
这是一个SAS的正则表达式例子,或者说,这是Perl正则表达式的例子,因为SAS里的正则表达就是按照Perl来的。
好吧,有点绕口,您请看下面这个图:也就是说,这个双引号是SAS的语法,但里面的内容是标准的Perl正则表达式,看到那个斜杠 / 没有?那是默认的Perl分隔符。
如果您因此认为应该去找一本Perl的书去啃一啃,那就误会我的意思了,我只是告诉你这个事实而已,您只要关注数说工作室的连载就可以弄明白正则表达式。当然拿一本Perl的书学一学也是极好的。
好了,下面我们就要重点研究一下两腿之间....哦不,两个斜杠//之间的秘密,我们可以在两个斜杠之间放置一些元字符(metacharacter),来简化一些很复杂的表达。
metacharacter用来简化表达某种意思,比如在word中我们都知道
代表的是制表符,那么在SAS正则表达式中也类似有:
^代表一段话的开头,
$代表一段话的结束,
s代表的是一个空格(space)
……
他们就是metacharacter。
很抽象吧?所以我才要结合这个PRAXMATCH来介绍metacharater…
2.2 例子
来看一段代码:
data _null_;
string1 = "I love Shushuo jun";
string2 = "Shushuo jun loves you";
a = PRXMATCH("/^Shu/",string1);
b = PRXMATCH("/^Shu/",string2);
file print;
put a= b=;
run;
运行结果如下:
所以简单来说,PRXMATCH(“/^Shu/”,string)匹配的是string的开头:开头是Shu,那么返回1,开头不是,则返回0。
string1开头不是Shu,故a返回0,string开头是Shu,故返回1。
我们学习了 ^ 这个metacharacter,它代表开头匹配,再学习几个:
- $代表结尾匹配;
- i代表不区分大小写;
- d 匹配任何某1个以上数位
- ddd 匹配任何某3个以上数位
先对这四个元字符举例:
运行结果为:data _null_;
string1="I love Shushuo jun";
string2="Shushuo jun loves you";
a=PRXMATCH("/jun$/",string1);
b=PRXMATCH("/jun$/",string2);
c=PRXMATCH("/JUN/i",string1);
d=PRXMATCH("/JUN/",string1);
string3="12";
string4="12a";
string5="122";
string6="1222";
e=PRXMATCH("/ddd/",string3);
f=PRXMATCH("/ddd/",string4);
g=PRXMATCH("/ddd/",string5);
h=PRXMATCH("/ddd/",string6);
file print;
put a= b= c= d= e= f= g= h=;
run;
解释:
1)注意$和i的使用位置:”/jun$/”和”/jun/i”,一个在斜杠里,一个在外。
2)a和b中,只有a返回了jun的位置,因为string1中,jun在末尾。
3)c和d中,只有c返回了,因为JUN是大写,必须用i符号,表示不区分大小写。
4)e、f返回的是0,因为ddd要求必须至少要有3个数位。所以g、h返回的是1。
2.3 metacharater总结
我们给出一些metacharater总结,供以后使用的时候查询:
正则表达式
String
返回
不匹配(返回0)
/jun/
“Shushuo jun”
9
“Shushuo shuai”
/^jun/
“jun, I love you”
1
“I love you, jun”
/jun$/
“I love you, jun”
13
“jun, I Iove you”
/jun/i
“Shushuo jUn”
9
“Shushuo, xiong”
/ddd /
“111”, “123”, ”328”…)
1
“1256”, “87”…
/ddd?/
“123”, “42”…(2或3个数位)
?可以让前面那一个字符可有可无
1
“1”, “1a1”, “4 9”…
/ddd+/
“123”, “345454”…(>=3个数位)
+可以返回前面表达式+更多任何位
1
“1”, “12”…
/ddd*/
“123”, ”12”, “3212”…(>=2个数位)
*返回前面表达式少一位或更多任何位
1
“1”,”xyx”…
/d{n}/
{n}表示匹配前面数位的n倍
{n,}表示匹配前面数位n倍以上
{n,m}表示匹配前面数位n倍以上,但不超过m倍
/s.u/
“shu”, ”s1u”, ”swwwwu”, ”s u”
1
“su”, “qu”…
/[1-5]d[6-9]/
“269”,”537”…(首位是1-5、末尾是6-9的数)
1
“769”,”243”…
/(d|x)d/
“23”, “x6”…(d|x表示数位或者字符串x)
x|y表示匹配x或y
1
“2e”,”ty”…
/[^a-e]/
“r”, “t”…(除了a-e的任何字符串)
1
“c”,”e”…
/D/
“ ”, “q”, “y”…(非数位符)
1
“1”, ”5”…
)
“)” 返回左括号
(
“(” 返回右括号
#//#
“//”
////
好了,我们现在要开始解释小王是怎么解决那个产品列表的问题的了。
再重述一遍问题文中最开始的那个问题:
下面是某超市自己的产品列表,有的是编号,有的是产品的名字,我们现在用正则表达式,将产品编号的行(红色字体的)读取到SAS数据集中。
Name
(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
......(未显示完)
3.2 问题理解
首先我们意义理解一下,我们只要有产品编号的行,产品编号的格式为:
1)有的编号前面有字母PD,它标志出过期的产品。
2)有的编号()后面还有一个空格,比如(12) 6753-5513。
综上所述,正则表达式应该这样“编码”:
编号
综上解释,我们给出小王的代码:
运行结果为:这里为方便解释,产品名单我们就用显示出来的那几个,你可能会说:data production;
input name $char20.;
a=PRXMATCH("/(dd) ?d{4}-d{4}/",name);
if a GT 0 then output;
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
;
proc print noobs;
title 'Production ID';
var name;
run;
肯定有没考虑到的情况,所以才有下一集啊。产品名单里也许还有其他没考虑到的情况呢?你的正则表达式一定可靠吗?
【SAS Says】是数说工作室更新的SAS系列学习笔记,旨在跟大家分享SAS数据分析的乐趣。
基础篇:
1. SAS软件入门
2. 读取数据
3. 描述数据
4. ODS的使用
5. 开发数据(一)
6. 开发数据(二)
7. SAS宏初步
8. 相关、回归等初步统计
回复【sasbase】查看
进阶篇
SAS的统计分析,包括假设检验、回归、非参数统计等等,晚些与大家见面。
扩展篇:
IML(矩阵交互模块):回复【sasiml】查看
数说工作室
关注 数说工作室
微信扫一扫关注公众号