在字符串处理中经常会使用到正则表达式,例如从HTML源码中或事件日志中获取目标数据,一般可以通过正则表达式完成任务。在我看来,所谓正则表达式就是根据字符串中的规律书写的一种表达式,关键点是发现规律。根据我的工作应用场景,字符串处理中最为常见的四种手段有“拆、替、抽、取”,具体来讲就是:
例如,邮箱“[email protected]”,我想把邮箱的地址和域名拆分开来,就需要按照“@”符,对字符串进行拆分。
例如,从网站抓取下来的数据往往是这样显示的:带千分位符的数据“12,345,678”或带百分号的数据“84.23%”。这样的数据其实是字符型的数值,无法进行四则运算,这就需要把千分位符或百分位符剔除(即用空字符串代替)。
例如,将QQ聊天记录下载下来是这样的:
如何抽取出每次发言的时间和对应的QQ号两个字段,这就需要字符串的抽取手段。
例如,将身份证号(123456198907177890)中的出生日期取出来,而出生日期正好是身份证号中某段连续的子集。
介绍完上面常用的4种字符串处理方法,接下来我们来讲讲正则表达式都有哪些?
常用的正则含义如下图所示,字符串的规律(正则表达式)可以通过这些元字符的组合体现。
最后我们来看看,R语言是如何结合正则表达式完成上面所讲的4种字符串处理方法
,这里我们强烈推荐stringr包,里面提供了“拆、替、抽、取”的专用函数,个人觉得远比R自带的grep、regexp、strsplit、sub等函数好用。
拆
:str_split
str_split(string, pattern, n = Inf, simplify = FALSE)
string:指定需要处理的字符串向量
pattern:分隔符,可以是复杂的正则表达式
n:指定切割的份数,默认所有符合条件的字符串都会被拆分开来
simplify:是否返回字符串矩阵,默认以列表的形式返回
例子:
# 用@或-将字符串切割开来
str_split(c('[email protected]','0511-87208801'), '[@-]')
以列表的形式返回结果。
例子:
例如数据表中有一列邮箱字段,如何把地址和域名两部分拆分开来存储到新的两列中?
email
'[email protected]','[email protected]')
# 结合sapply函数获得@分隔符前面和后面的内容
add
doman
df
df
替
:str_replace与str_replace_all
str_replace(string, pattern, replacement)
str_replace_all(string, pattern, replacement)
string:字符串向量
pattern:被替换的子字符串,可以是复杂的正则表达式
replacement:用来替换的字符串
两个函数的区别在于,前面函数只替换首次满足条件的子字符串,后面的函数可以替换所有满足条件的子字符串。
例子:
#将含有千分位符或百分位符的数据转换为数值型数据
commadata
percentdata
commadatanew
percentdatanew
commadatanew
percentdatanew
抽
:str_extract和str_extract_all
str_extract(string, pattern)
str_extract_all(string, pattern, simplify = FALSE)
string:字符串向量
pattern:抽取出满足条件的子字符串,往往使用正则表达式
simplify:是否返回字符串矩阵,默认以列表的形式返回
两个函数的区别在于,前面函数只抽取出首次满足条件的子字符串,后面的函数可以抽取出所有满足条件的子字符串。当前面的函数没有匹配到抽取的结果,则返回NA,而后面的函数在没有匹配到抽取的结果时返回character(0)。
例子:
# 抽取出字符串中的日期和流量值
s
'date:2017-04-16,pv:201233','date:2017-04-17,pv:324123')
date
pv
unlist(date)
unlist(pv)
结果中的pv两竟然还是包含'pv:'字符串,实际上我用了圆括号,只想取出pv对于的数值,却没有起作用。难道R中圆括号不起作用吗?这里还需要跟大家结束另一个"抽"的函数:str_match_all。
str_match(string, pattern)
str_match_all(string, pattern)
函数参数的含义同str_extract。
pv
pv
pv