上篇介绍了stringr
工具包的一些字符串处理函数。实际上,str_*()
系列的多数函数都经常会使用到正则表达式(regular expression)来进行模式匹配。因此在介绍这些函数之前,本篇先来介绍正则表达式。详见base
工具包的regex
。
library(stringr)
转义符
正则表达式的特点是“所写非所见”,而转义符的作用就是强制使“所写即所见”。转义符使用反斜杠\
表示。
例1
书写字符串时需要在首尾加上双引号""
或单引号''
,但是字符串的内容本身是不包括这些引号的。因此,想要得到一个包含引号的字符串字符串"
,通过书写以下代码会出现报错:
x <- "字符串""

引号在字符串中有特殊的功能,即作为字符串开始和结束的标志;当引号第二次出现时也意味着字符串的结束,其后不能再有其他内容;
上面代码中,作为字符串内容的引号会被视为字符串结束的标志,而原本作为结束标志的引号反而变得多余,因此报错。
解决办法是在作为字符串内容的引号前加上转义符\
:
x <- "字符串\""
x
## [1] "字符串\""
par(plt = c(0.05,0.95,0,1), ps = 20, adj = 0,
family = "mono")
plot(1:6, type = "n", axes = F, ann = F)
text(1,3, labels = x)

虽然在R的输出界面上还可以看到字符串内包含转义符;但作为文本打印在图片上时,转义符不会出现。
例2
反斜杠\
作为转义符,那么如何在字符串内包含反斜杠呢?
转义符同样可以转义自身,因此使用两个反斜杠\\
即可使字符串内包含一个反斜杠。
x <- "字符串\\"
x
## [1] "字符串\\"
par(plt = c(0.05,0.95,0,1), ps = 20, adj = 0,
family = "mono")
plot(1:6, type = "n", axes = F, ann = F)
text(1,3, labels = x)

两个反斜杠含义不同:第一个反斜杠表示转义符,第二个反斜杠仅表示一种待转义的特殊符号;
如果想要包含两个连续的反斜杠,需要使用四个反斜杠;以此类推。
电脑中的文件夹地址一般也使用反斜杠来间隔,但由于反斜杠本身又是转义符,因此在R中输入文件地址时需要使用双反斜杠或单正斜杠:
## 错误
setwd("C:\Usere"
## 正确
setwd("C:\\Usere")
## 正确
setwd("C:/Usere")
换行符
在word中当超过一行容量时会自动换行,需要换段时可以按Enter键;而在纯文本格式的文件中,这些操作都需要使用字符来记录。换行符对应的正则表达式是\n
。
x <- "字符\n串"
par(plt = c(0.05,0.95,0,1), ps = 20, adj = 0,
family = "mono")
plot(1:6, type = "n", axes = F, ann = F)
text(1,3, labels = x)

同样,想要在字符串中包含符号\n
本身,也可以使用转义符:
x <- "字符\\n串"
par(plt = c(0.05,0.95,0,1), ps = 20, adj = 0,
family = "mono")
plot(1:6, type = "n", axes = F, ann = F)
text(1,3, labels = x)

定位符
使用模式匹配的str_*()
系列函数拥有一个参数pattern
,它们通常使用匹配符来进行赋值。
定位符属于匹配符的一种,其中^
表示字符串的开始;$
表示字符串的结束。\b
表示文本字符开始或结束的位置,即介于文本字符与非文本字符之间的位置;\B
是\b
的补码,表示介于两个文本字符或两个非文本字符之间的位置。
以str_replace_all()
函数为例,它可以替换掉字符串中所包含特定模式的部分:
str_replace_all(string, pattern, replacement)
pattern:匹配模式;
replacement:作为替代的字符。
比如检索单词abstract
是否包含字母t
的三种情况:
是否包含字母
t
;是否在开头包含字母
t
;是否在结尾包含字母
t
。
对应的代码及其结果如下:
str_replace_all("abstract", "t", "_")
## [1] "abs_rac_"
str_replace_all("abstract", "^t", "_")
## [1] "abstract"
str_replace_all("abstract", "t$", "_")
## [1] "abstrac_"
将所有文本字符开始或结束的位置替换成下划线_
:
str_replace_all("Are you OK", "\\b", "_")
## [1] "_Are_ _you_ _OK_"
通配符
通配符也属于匹配符,它包含两个层次:
可以代替任意字符的特殊符号;
可以代替特定类型内的任意字符的特殊符号。
通配符 | 含义 |
---|---|
. | 任意一个字符 |
\d | 十进制数字 |
\D | \d的补码;十进制数字以外的任意一个字符 |
\s | 任意一个空白型字符,包括空格、Tab、换页符等 |
\w | 任意一个文本字符,包括字母、十进制数字、下划线_ |
\W | \w的补码;任意一个非文本字符 |
str_replace_all("abstract", "t.a", "_")
## [1] "abs_ct"
str_replace_all("abstract", "t..a", "_")
## [1] "abstract"
abstract
存在tra
的部分,因此t.a
模式可以被匹配;
abstract
不存在t
和a
间隔两个字母的部分,因此t..a
模式不能被匹配;
x <- "abstract is necessary \n1. Introduction"
str_replace_all(x, "\\d", "_")
## [1] "abstract is necessary \n_. Introduction"
使用带反斜杠的匹配符时需要在其前再加上一个反斜杠进行转义。
通配符也可以使用中括号[]
进行自定义,表示括号内的任意一个字符。
str_replace_all("abstract", "t[r,s]a", "_")
## [1] "abs_ct"
[r,s]
表示字母r
和s
中的任意一个,因此只要tra
和tsa
中任意一个存在,t[r,s]a
都能被匹配。
竖杠|
表示前后整体的“或”,若为部分之间的“或”需要使用小括号:
str_replace_all("abstract", "tr|sa", "_")
## [1] "abs_ct"
str_replace_all("abstract", "t(r|s)a", "_")
## [1] "abs_ct"
系统中预定义的包含中括号的通配符及其含义:
通配符 | 含义 |
---|---|
| | 或 |
[:digit:] | 数字 |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:alnum:] | 大小写字母、数字 |
[:blank:] | 空格、制表符Tab |
[:space:] | 空白型字符,范围比[:blank:]更大,包括换行符、换页符、回车符等 |
[:punct:] | 标点符号,包括如下:! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { |
[:graph:] | 大小写字母、数字、标点符号 |
[:print:] | 大小写母、数字、标点符号、空格 |
[:xdigit:] | 十六进制字符,包括如下:1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f |
[\u4e00-\u9fa5] | 汉字字符 |
# 是否包含数字
str_replace_all("abstract123", "[:digit:]", "_")
## [1] "abstract___"
# 是否包含大写字母
str_replace_all("abstractABC", "[:upper:]", "_")
## [1] "abstract___"
str_replace_all("摘要ABC", "[\u4e00-\u9fa5]", "_")
## [1] "__ABC"
限定符
上述例中曾使用两个点号..
表示连续的两个任意字符。对此,限定符(Repetition)提供了更为简洁和灵活的表达方式。
限定符用来限制它前面的字符连续出现的次数。常见的限定符如下:
限定符 | 数目限制 |
---|---|
? | 至多出现一次,即0次或1次 |
* | 可以出现任意次,包括0次 |
+ | 至少出现1次 |
{n} | 刚好出现n次 |
{n,} | 至少出现n次 |
{n,m} | 至少出现n次且至多出现m次 |
str_detect("abstract", "t..?a")
## [1] TRUE
str_detect("abstract", "t..*a")
## [1] TRUE
str_detect("abstract", "t..+a")
## [1] FALSE
str_detect("abstract", "t.{1}a")
## [1] TRUE
当限定符所限定的是多个字符的组合时,需要使用小括号:
str_detect("banana", "an{2}")
## [1] FALSE
str_detect("banana", "(an){2}")
## [1] TRUE
结语
本篇只是对正则表达式做了一个比较系统地介绍,并未包含所有的正则表达式。