R语言与正则表达式

R语言在提取字符串上有着强大的能力,其中字符串可以看做为文本信息。今天需要跟大家介绍一款更为通用、更加底层的文本信息提取工具——正则表达式。

所谓正则表达式,即使用一个字符串来描述、匹配一系列某个语法规则的字符串。通过特定的字母、数字以及特殊符号的灵活组合即可完成对任意字符串的匹配,从而达到提取相应文本信息的目的。在R语言中,有两种风格的正则表达式可以实现,一种就是在基本的正则表达式基础上进行扩展,这和相应的R字符串处理函数相关,另一种就是Perl正则表达式,这种风格的正则我们在R中一般不常用,本文主要还是针对R默认的基础的正则表达式风格进行讲解。 正则表达式是对字符串类型数据进行匹配判断,提取等操作的一套逻辑公式。

处理字符串类型数据方面,高效的工具有Perl和Python。如果我们只是偶尔接触文本处理任务,则学习Perl无疑成本太高;如果常用Python,则可以利用成熟的正则表达式模块:re库;如果常用R,则使用Hadley大神开发的stringr包则已经能够游刃有余。

下面,我们先简要介绍重要并通用的正则表达式规则。接着,总结一下stringr包中重要的字符处理函数。

元字符

正则表达式中,有12个字符被保留用作特殊用途。他们分别是:

[ ] \ ^ $ . | ? * + ( )

它们的作用如下:

  • [ ]:括号内的任意字符将被匹配;
  • \:具有两个作用:
    • 1.对元字符进行转义
    • 2.一些以\开头的特殊序列表达了一些字符串组
  • ^:匹配字符串的开始.将^置于character class的首位表达的意思是取反义。如[^5]表示匹配除了”5”以外的任何字符。
  • $:匹配字符串的结束。但将它置于character class内则消除了它的特殊含义。如[akm$]将匹配’a’,’k’,’m’或者’$’.
  • .:匹配除换行符以外的任意字符。
  • |:或者
  • ?:前面的字符(组)最多被匹配一次
  • *:前面的字符(组)将被匹配零次或多次
  • +:前面的字符(组)将被匹配一次或多次
  • ( ):表示一个字符组,括号内的字符串将作为一个整体被匹配。

重复

代码

含义说明

?

重复零次或一次

*

重复零次或多次

+

重复一次或多次

{n}

重复n次

{n,}

重复n次或更多次

{n,m}

重复n次到m次

转义

如果我们想查找元字符本身,如”?”和”*“,我们需要提前告诉编译系统,取消这些字符的特殊含义。这个时候,就需要用到转义字符\,即使用\?\*.当然,如果我们要找的是\,则使用\\进行匹配。

注:R中的转义字符则是双斜杠:\\

R中预定义的字符组

代码

含义说明

[:digit:]

数字:0-9

[:lower:]

小写字母:a-z

[:upper:]

大写字母:A-Z

[:alpha:]

字母:a-z及A-Z

[:alnum:]

所有字母及数字

[:punct:]

标点符号,如. , ;等

[:graph:]

Graphical characters,即[:alnum:]和[:punct:]

[:blank:]

空字符,即:Space和Tab

[:space:]

Space,Tab,newline,及其他space characters

[:print:]

可打印的字符,即:[:alnum:],[:punct:]和[:space:]

代表字符组的特殊符号

代码

含义说明

\w

字符串,等价于[:alnum:]

\W

非字符串,等价于[^[:alnum:]]

\s

空格字符,等价于[:blank:]

\S

非空格字符,等价于[^[:blank:]]

\d

数字,等价于[:digit:]

\D

非数字,等价于[^[:digit:]]

\b

Word edge(单词开头或结束的位置)

\B

No Word edge(非单词开头或结束的位置)

\<

Word beginning(单词开头的位置)

\>

Word end(单词结束的位置)


stringr包中的重要函数

函数

功能说明

R Base中对应函数

使用正则表达式的函数

str_extract()

提取首个匹配模式的字符

regmatches()

str_extract_all()

提取所有匹配模式的字符

regmatches()

str_locate()

返回首个匹配模式的字符的位置

regexpr()

str_locate_all()

返回所有匹配模式的字符的位置

gregexpr()

str_replace()

替换首个匹配模式

sub()

str_replace_all()

替换所有匹配模式

gsub()

str_split()

按照模式分割字符串

strsplit()

str_split_fixed()

按照模式将字符串分割成指定个数

-

str_detect()

检测字符是否存在某些指定模式

grepl()

str_count()

返回指定模式出现的次数

-

其他重要函数

str_sub()

提取指定位置的字符

regmatches()

str_dup()

丢弃指定位置的字符

-

str_length()

返回字符的长度

nchar()

str_pad()

填补字符

-

str_trim()

丢弃填充,如去掉字符前后的空格

-

str_c()

连接字符

paste(),paste0()

可见,stringr包中的字符处理函数更丰富和完整(其实还有更多函数),并且更容易记忆。或许速度也会更快。


其他相关的重要函数

windows下处理字符串类型数据最头疼的无疑是编码问题了。这里介绍几个编码转换相关的函数。

函数

功能说明

iconv()

转换编码格式

Encoding()

查看编码格式;或者指定编码格式

tau::is.locale()

tests if the components of a vector of character are in the encoding of the current locale

tau::is.ascii()

tau::is.utf8()

tests if the components of a vector of character are true UTF-8 strings

R默认的正则表达式风格包括基础文本处理函数和stringr包中的文本处理函数。在R中二者都支持正则表达式,也都具备基本的文本处理能力,但基础函数的一致性要弱很多,在函数命名和参数定义上很难让人印象深刻。stringr包是Hadley Wickham开发了一款专门进行文本处理的R包,它对基础的文本处理函数进行了扩展和整合,在一致性和易于理解性上都要优于基础函数。本文在介绍基本的正则表达式语法的基础上,通过R中这两种文本处理函数进行实例说明,也好让大家对R语言中正则表达式的基本用法有个大致了解,在后续的爬虫演练中更容易理解一些信息提取的细节知识。

基本的正则表达式语法

实际应用中正则表达式的一个比较经典的使用场景是识别电子邮箱地址。一个正常的电子邮箱账户应该由下面几部分构成:任意字符、数字和符号组成的用户名+@+.+com/net等域名。根据正则表达式的语法规则,我们就可以由这几部分写出邮箱账户的正则表达式:

[A-Za-z0-9._+]+@[A-Za-z0-9]+.(com|org|edu|net)

其中:

[A-Za-z0-9._+]+:A-Z表示匹配任意的A-Z大写字母,所有可能的组合放在中括号里表示可以匹配其中的任一个,加号表示任意字符可以出现1次或者多次,\表示转义,因为.在正则表达式中有特殊含义,想要正常的表达.号必须使用转义符。

@:邮箱必须的一个符号。

[A-Za-z0-9]:同前面一样,@符号后面必须有一个包含运营商信息的字符串。

.:邮箱地址中必须要有的一个点号。

(com|org|edu|net):列出邮箱地址可能的域名系统,括号内表示分组处理,|符号表示或的含义。

image.jpeg

另外也有一些在线测试正则表达式的网页,大家可以拿来练手,小编这里也推荐一个:

https://www.regexpal.com/

image.jpeg

R中基础文本处理函数和stringr包文本处理函数对于正则表达式的支持情况如下表所示:

image.png

基础文本处理函数中正则表达式的应用

R中常用的支持正则表达式的基础文本处理函数包括grep/grepl、sub/gsub、regexpr/gregexpr等。

example_text1 <- c("23333#RRR#PP","35555#CCCC","louwill#2017")
  • 以#进行字符串切分
unlist(strsplit(example_text1, "#"))

[1] "23333"   "RRR"     "PP"      "35555"   "CCCC"    "louwill" "2017"
  • 以空字符集进行字符串切分
unlist(strsplit(example_text1, "\\s"))

[1] "23333#RRR#PP" "35555#CCCC"   "louwill#2017"
  • 以空字符替换字符串第一个#匹配
sub("#","", example_text1)

[1] "23333RRR#PP" "35555CCCC"   "louwill2017"
  • 以空字符集替换字符串全部#匹配
gsub("#","",example_text1)

[1] "23333RRRPP"  "35555CCCC"   "louwill2017"
  • 查询字符串中是否存在3333或5555的特征并返回所在位置
grep("[35]{4}", example_text1)

[1] 1 2
  • 查询字符串中是否存在3333或5555的特征并返回逻辑值
grepl("[35]{4}", example_text1)

[1]  TRUE  TRUE FALSE
  • 返回匹配特征的字符串
pattern <- "[[:alpha:]]*(,|#)[[:alpha:]]"

m <- regexpr(pattern, example_text1)

regmatches(example_text1, m)

[1] "#R" "#C"

stringr包文本处理函数中的正则表达式的应用

stringr包一共为我们提供了30个字符串处理函数,其中大部分均可支持正则表达式的应用,包内所有函数均以str_开头,后面单词用来说明该函数的含义,相较于基础文本处理函数,stringr包函数更容易直观地理解。本文仅以str_extract和str_extract_all函数为例,对stringr包的正则表达式应用进行简要说明。

example_text2 <- "1\. A small sentence. - 2\. Another tiny sentence."

library(stringr)
  • 提取small特征字符
str_extract(example_text2, "small")

[1] "small"
  • 提取包含sentence特征的全部字符串
unlist(str_extract_all(example_text2, "sentence"))

[1] "sentence" "sentence"
  • 提取以1开始的字符串
str_extract(example_text2, "^1")

[1] "1"
  • 提取以句号结尾的字符
unlist(str_extract_all(example_text2, ".$"))

[1] "."
  • 提取包含tiny或者sentence特征的字符串
unlist(str_extract_all(example_text2, "tiny|sentence"))

[1] "sentence" "tiny"     "sentence"
  • 点号进行模糊匹配
str_extract(example_text2, "sm.ll")

[1] "small"
  • 中括号内表示可选字符串
str_extract(example_text2, "sm[abc]ll")

[1] "small"

str_extract(example_text2, "sm[a-p]ll")

[1] "small"

对于特定的字符我们可以手动指定,比如[a-z A-Z]表示a-z和A-Z之间的所有字母,但R预先定义了一些字符集方便大家调用,如下表所示。

image.png

str_extract(example_text2, "([[:alpha:]]).+?\\1")

[1] "A small sentence. - 2\. A"

除此之外,R中正则表达式的应用还有若干简化的形式,它被分配给几个特定的字符类,如下表所示:

image.jpeg

  • 提取全部单词字符
unlist(str_extract_all(example_text2, "\\w+"))

[1] "1"        "A"        "small"    "sentence" "2"        "Another"  "tiny"    

[8] "sentence"

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券