《R数据科学》学习笔记|Note9:使用stringr处理字符串(上)

简介: 本周内容较多且杂,故分成上下两篇。正则表达式是从左到右来匹配一个字符串的。“Regular Expression”这个词太长了,我们通常使用它的缩写“regex”或者“regexp”。 正则表达式可以被用来替换字符串中的文本、验证表单、基于模式匹配从一个字符串中提取字符串等等。

9.1 简介


本章将介绍 R 中的字符串处理。包括字符串的基本工作原理,以及如何手工创建字符串,但本章的重点是正则表达式(regular expression,regexp)。正则表达式的用处非常大,字符串通常包含的是非结构化或半结构化数据,正则表达式可以用简练的语言来描述字符串中的模式。


9.2 字符串基础


可以使用单引号或双引号来创建字符串。与其他语言不同,单引号和双引号在 R 中没有区别。我们推荐使用 ",除非你想要创建包含多个 " 的一个字符串:

string1 <- "This is a string"
string2 <- 'To put a "quote" inside a string, use single quotes'

如果忘记了结尾的引号,你会看到一个 +,这是一个续行符:

> "This is a string without a closing quote
+

如果遇到了这种情况,可以按 Esc 键,然后重新输入。


如果想要在字符串中包含一个单引号或双引号,可以使用 \ 对其进行“转义”:

double_quote <- "\"" # or '"'
single_quote <- '\'' # or "'"

这意味着,如果想要在字符串中包含一个反斜杠,就需要使用两个反斜杠:\\。


字符串的打印形式与其本身的内容不是相同的,因为打印形式中会显示出转义字 符。如果想要查看字符串的初始内容,可以使用 writelines() 函数:

x <- c("\"", "\\")
x
> [1] "\"" "\\"
writeLines(x)
> "
> \

还有其他几种特殊字符。最常用的是换行符 \n 和制表符 \t,你可以使用 ?'"' 或 ?"'" 调 出帮助文件来查看完整的特殊字符列表。


多个字符串通常保存在一个字符向量中,使用 c() 函数来创建字符向量:

c("one", "two", "three")
> [1] "one" "two" "three"

9.2.1 字符串长度


stringr 中的函数比R基础包中的字符串处理函数名称更直观,并且都是以 str_ 开头的。例如,str_length() 函数可以返回字符串中的字符数量:

str_length(c("a", "R for data science", NA))
> [1] 1 18 NA

9.2.2 字符串组合


要想组合两个或更多字符串,可以使用 str_c() 函数:

str_c("x", "y")
> [1] "xy"
str_c("x", "y", "z")
> [1] "xyz"

可以使用 sep 参数来控制字符串间的分隔方式:

str_c("x", "y", sep = ", ")
> [1] "x, y"

和多数 R 函数一样,缺失值是可传染的。如果想要将它们输出为 “NA”,可以使用 str_ replace_na():

x <- c("abc", NA)
str_c("|-", x, "-|")
> [1] "|-abc-|" NA
str_c("|-", str_replace_na(x), "-|")
> [1] "|-abc-|" "|-NA-|"

如以上代码所示,str_c() 函数是向量化的,它可以自动循环短向量,使得其与最长的向量具有相同的长度:

str_c("prefix-", c("a", "b", "c"), "-suffix")
> [1] "prefix-a-suffix" "prefix-b-suffix" "prefix-c-suffix"

长度为 0 的对象会被无声无息地丢弃。这与 if 结合起来特别有用:

name <- "Hadley"
time_of_day <- "morning"
birthday <- FALSE
str_c(
 "Good ", time_of_day, " ", name,
 if (birthday) " and HAPPY BIRTHDAY", # birthday 为True时,才会打印后面的语句
 "."
)
> [1] "Good morning Hadley."

要想将字符向量合并为字符串,可以使用 collapse() 函数:

str_c(c("x", "y", "z"), collapse = ", ")
> [1] "x, y, z"

9.2.3 字符串取子集


可以使用 str_sub() 函数来提取字符串的一部分。除了字符串参数外,str_sub() 函数中还 有 start 和 end 参数,它们给出了子串的位置(包括 start 和 end 在内):

x <- c("Apple", "Banana", "Pear")
str_sub(x, 1, 3) # 开始、结束的位置参数
> [1] "App" "Ban" "Pea"
# 负数表示从后往前数
str_sub(x, -3, -1)
> [1] "ple" "ana" "ear"

注意,即使字符串过短,str_sub() 函数也不会出错,它将返回尽可能多的字符:

str_sub("a", 1, 5)
> [1] "a"

还可以使用 str_sub() 函数的赋值形式来修改字符串:

str_sub(x, 1, 1) <- str_to_lower(str_sub(x, 1, 1)) #函数将文本转换为小写
x
> [1] "apple" "banana" "pear"


9.3 使用正则表达式进行模式匹配


我们通过 str_view() 和 str_view_all() 函数来学习正则表达式。这两个函数接受一个字符向量和一个正则表达式,并显示出它们是如何匹配的。


9.3.1 基础匹配


最简单的模式是精确匹配字符串 :

x <- c("apple", "banana", "pear")
str_view(x, "an")

image.png


另一个更复杂一些的模式是使用 .,它可以匹配任意字符(除了换行符):

str_view(x, ".a.")

image.png


但是,如果 . 可以匹配任意字符,那么如何匹配字符 . 呢?你需要使用一个**“转义”符号来告诉正则表达式实际上就是要匹配 . 这个字符,而不是使用 . 来匹配其他字符。和字符串一样,正则表达式也使用反斜杠**来去除某些字符的特殊含义。因此,如果要匹配 .,那么你需要的正则表达式就是 \.。遗憾的是,这样做会带来一个问题。因为我们使用字符串来表示正则表达 式,而且 \ 在字符串中也用作转义字符,所以正则表达式 \. 的字符串形式应是 \\.:

# 要想建立正则表示式,我们需要使用\\
dot <- "\\."
# 实际上表达式本身只包含一个\:
writeLines(dot)
#> \.
# 这个表达式告诉R搜索一个.
str_view(c("abc", "a.c", "bef"), "a\\.c")

image.png


如果 \ 在正则表达式中用作转义字符,那么如何匹配 \ 这个字符呢?我们还是需要去除其特殊意义,建立形式为 \\ 的正则表达式。要想建立这样的正则表达式,我们需要使用一个字符串,其中还需要对 \ 进行转义。这意味着要想匹配字符 \,我们需要输入 “\\\\”—— 你需要 4 个反斜杠来匹配 1 个反斜杠!

x <- "a\\b"
writeLines(x)
> a\b
str_view(x, "\\\\")

image.png


9.3.2 锚点


默认情况下,正则表达式会匹配字符串的任意部分。有时我们需要在正则表达式中设置锚点,以便 R 从字符串的开头或末尾进行匹配。我们可以设置两种锚点:


^ 从字符串开头进行匹配。


$ 从字符串末尾进行匹配。

x <- c("apple", "banana", "pear")
str_view(x, "^a")
str_view(x, "a$")

image.png


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WMEMTfXq-1614859189166)(F:\HJH\mzbj\9\15.png)]


始于权力(^),终于金钱($)


如果想要强制正则表达式匹配一个完整字符串,那么可以同时设置 ^ 和 $ 这两个锚点:

x <- c("apple pie", "apple", "apple cake")
str_view(x, "apple")

image.png

str_view(x, "^apple$")

image.png


还可以使用 \b 来匹配单词间的边界。例如,为了避免匹配到 summarize、summary、rowsum 等,我们会使用 \bsum\b 进行搜索。


9.3.3 字符类与字符选项


很多特殊模式可以匹配多个字符。我们已经介绍过 .,它可以匹配除换行符外的任意字符。 还有其他 4 种常用的字符类。


\d 可以匹配任意数字。

\s 可以匹配任意空白字符(如空格、制表符和换行符)。

[abc] 可以匹配 a、b 或 c

[^abc] 可以匹配除 a、b、c 外的任意字符。

牢记,要想创建包含 \d 或 \s 的正则表达式,你需要在字符串中对 \ 进行转义,因此需 要输入 “\\d” 或 “\\s”。


你还可以使用字符选项创建多个可选的模式。例如,abc|d..f 可以匹配 abc 或 deaf。注 意,因为 | 的优先级很低,所以 abc|xyz 匹配的是 abc 或 xyz,而不是 abcyz 或 abxyz。与 数学表达式一样,如果优先级让人感到困惑,那么可以使用括号让其表达得更清晰一些:

str_view(c("grey", "gray"), "gr(e|a)y")

image.png


9.3.4 重复


正则表达式的另一项强大功能是,其可以控制一个模式能够匹配多少次。


?:0 次或 1 次。

+: 1 次或多次。

*:0 次或多次。

x <- "1888 is the longest year in Roman numerals: MDCCCLXXXVIII"
str_view(x, "CC?")

image.png

str_view(x, "CC+")

image.png

str_view(x, 'C[LX]+')

image.png


注意,这些运算符的优先级非常高,因此使用 colou?r 既可以匹配 color,也可以匹配 colour。这意味着很多时候需要使用括号,比如 bana(na)+。


还可以精确设置匹配的次数。


{n}:匹配 n 次。

{n,}:匹配 n 次或更多次。

{,m}:最多匹配 m 次。

{n, m}:匹配 n 到 m 次。

str_view(x, "C{2}")
str_view(x, "C{2}")
str_view(x, "C{2}")
#大家自行观察

默认的匹配方式是“贪婪的”:正则表达式会匹配尽量长的字符串。通过在正则表达式后面添加一个 ?,你可以将匹配方式更改为“懒惰的”,即匹配尽量短的字符串。

str_view(x, 'C{2,3}?')

image.png

str_view(x, 'C[LX]+?')

image.png


9.3.5 分组与回溯引用


前面学习了括号可以用于消除复杂表达式中的歧义。括号还可以定义“分组”, 你可以通过回溯引用(如 \1、\2 等)来引用这些分组。例如,以下的正则表达式可以找出名称中有重复的一对字母的所有水果:

fruit <- c("banana","coconut","cocumber","jujube","papaya","salal berry")
str_view(fruit, "(..)\\1", match = TRUE)

image.png


image.pngimage.png

相关文章
|
7月前
|
存储 JSON 数据格式
UCB Data100:数据科学的原理和技巧:第一章到第五章
UCB Data100:数据科学的原理和技巧:第一章到第五章
336 0
UCB Data100:数据科学的原理和技巧:第一章到第五章
【数据科学导论】实验六:字符串与字典
【数据科学导论】实验六:字符串与字典
42 0
|
Python
【数据科学导论】实验一:语法、变量和数据类型
【数据科学导论】实验一:语法、变量和数据类型
119 0
《R数据科学》学习笔记|Note10:使用stringr处理字符串(下)
《R数据科学》学习笔记|Note10:使用stringr处理字符串(下)
238 0
《R数据科学》学习笔记|Note10:使用stringr处理字符串(下)
|
大数据 数据处理
《R数据科学》学习笔记|Note6:使用tibble实现简单数据框
本系列为《R数据科学》(R for Data Science)的学习笔记。相较于其他R语言教程来说,本书一个很大的优势就是直接从实用的R包出发,来熟悉R及数据科学。更新过程中,读者朋友如发现错误,欢迎指正。如果有疑问,也可以在评论区留言或后台私信。希望各位读者朋友能学有所得!
559 0
《R数据科学》学习笔记|Note6:使用tibble实现简单数据框
|
资源调度 索引
《R数据科学》学习笔记|Note16:使用purrr实现迭代(下)
《R数据科学》学习笔记|Note16:使用purrr实现迭代(下)
131 0
《R数据科学》学习笔记|Note16:使用purrr实现迭代(下)
|
数据可视化
《R数据科学》学习笔记|Note14:向量
《R数据科学》学习笔记|Note14:向量
278 0
《R数据科学》学习笔记|Note14:向量
《R数据科学》学习笔记|Note5:使用dplyr进行数据转换(下)
本系列为《R数据科学》(R for Data Science)的学习笔记。相较于其他R语言教程来说,本书一个很大的优势就是直接从实用的R包出发,来熟悉R及数据科学。更新过程中,读者朋友如发现错误,欢迎指正。如果有疑问,也可以在评论区留言或后台私信。希望各位读者朋友能学有所得!
175 0
《R数据科学》学习笔记|Note5:使用dplyr进行数据转换(下)
《R数据科学》学习笔记|Note12:使用magrittr进行管道操作
《R数据科学》学习笔记|Note12:使用magrittr进行管道操作
179 0
《R数据科学》学习笔记|Note12:使用magrittr进行管道操作
《R数据科学》学习笔记|Note11:使用forcats处理因子
《R数据科学》学习笔记|Note11:使用forcats处理因子
158 0
《R数据科学》学习笔记|Note11:使用forcats处理因子