14 字符串
14.1 引言
到目前为止,你已经使用了很多字符串,但对细节知之甚少。现在是时候深入了解它们,学习字符串的运作原理,并掌握一些你可以使用的强大字符串处理工具。
我们将从创建字符串和字符向量的细节开始。然后,你将深入学习如何从数据创建字符串,以及反过来:如何从数据中提取字符串。接着,我们将讨论处理单个字母的工具。本章最后会介绍处理单个字母的函数,并简要讨论在处理其他语言时,你从英语中获得的期望可能会如何误导你。
我们将在下一章继续学习字符串,届时你将学到更多关于正则表达式的强大功能。
14.1.1 先决条件
在本章中,我们将使用 stringr 包中的函数,它是核心 tidyverse 的一部分。我们还将使用 babynames 数据,因为它提供了一些有趣的字符串供我们操作。
你可以很快分辨出你正在使用的是一个 stringr 函数,因为所有 stringr 函数都以 str_
开头。如果你使用 RStudio,这一点特别有用,因为输入 str_
会触发自动补全,让你回想起可用的函数。
14.2 创建字符串
我们在本书的前面部分已经顺便创建过字符串,但没有讨论细节。首先,你可以使用单引号 ('
) 或双引号 ("
) 来创建字符串。这两者在行为上没有区别,因此为了保持一致性,tidyverse 风格指南 建议使用 "
,除非字符串中包含多个 "
。
string1 <- "This is a string"
string2 <- 'If I want to include a "quote" inside a string, I use single quotes'
如果你忘记关闭引号,你会看到 +
,即续行提示符:
> "This is a string without a closing quote
+
+
+ HELP I'M STUCK IN A STRING
如果发生这种情况,而你又不知道该关闭哪个引号,可以按 Escape
键取消并重试。
14.2.1 转义
要在字符串中包含字面意义上的单引号或双引号,你可以使用 \
来“转义”它:
double_quote <- "\"" # 或者 '"'
single_quote <- '\'' # 或者 "'"
所以,如果你想在字符串中包含一个字面意义上的反斜杠,你需要对它进行转义:"\\"
:
backslash <- "\\"
请注意,字符串的打印表示形式与字符串本身不同,因为打印表示形式会显示转义符(换句话说,当你打印一个字符串时,你可以复制并粘贴输出来重新创建那个字符串)。要查看字符串的原始内容,请使用 str_view()
1:
14.2.2 原始字符串
创建一个包含多个引号或反斜杠的字符串很快就会变得混乱。为了说明这个问题,让我们创建一个字符串,它包含我们定义 double_quote
和 single_quote
变量的代码块的内容:
tricky <- "double_quote <- \"\\\"\" # or '\"'
single_quote <- '\\'' # or \"'\""
str_view(tricky)
#> [1] │ double_quote <- "\"" # or '"'
#> │ single_quote <- '\'' # or "'"
这可真是一大堆反斜杠!(这有时被称为倾斜的牙签综合症 (leaning toothpick syndrome)。)为了消除转义,你可以改用原始字符串 (raw string)2:
tricky <- r"(double_quote <- "\"" # or '"'
single_quote <- '\'' # or "'")"
str_view(tricky)
#> [1] │ double_quote <- "\"" # or '"'
#> │ single_quote <- '\'' # or "'"
原始字符串通常以 r"(
开始,以 )"
结束。但是,如果你的字符串包含 )"
,你可以改用 r"[]"
或 r"{}"
,如果这还不够,你可以插入任意数量的破折号来使开始和结束对唯一,例如 r"--()--"
、r"---()---"
等。原始字符串足够灵活,可以处理任何文本。
14.2.3 其他特殊字符
除了 \"
、\'
和 \\
,还有一些其他特殊字符可能会派上用场。最常见的是 \n
(换行符)和 \t
(制表符)。你有时还会看到包含以 \u
或 \U
开头的 Unicode 转义的字符串。这是一种书写非英文字符的方法,能在所有系统上工作。你可以在 ?Quotes
中看到其他特殊字符的完整列表。
请注意,str_view()
对制表符使用花括号,以便更容易发现它们3。处理文本的挑战之一是,空白字符有多种方式进入文本,所以这个背景能帮助你识别出有异常情况正在发生。
14.2.4 练习
-
创建包含以下值的字符串:
He said "That's amazing!"
\a\b\c\d
\\\\\\
-
在你的 R 会话中创建以下字符串并打印它。特殊的
\u00a0
发生了什么?str_view()
如何显示它?你能用 Google 搜索一下,找出这个特殊字符是什么吗?x <- "This\u00a0is\u00a0tricky"
14.3 从数据创建多个字符串
现在你已经学会了“手动”创建一个或两个字符串的基础知识,我们将深入探讨从其他字符串创建字符串的细节。这将帮助你解决一个常见问题:你有一些自己写的文本,想把它与数据框中的字符串结合起来。例如,你可能会将 “Hello” 与一个 name
变量结合起来,创建一个问候语。我们将向你展示如何使用 str_c()
和 str_glue()
来做到这一点,以及如何将它们与 mutate()
一起使用。这自然会引出一个问题:你可能会在 summarize()
中使用哪些 stringr 函数?因此,我们将在本节最后讨论 str_flatten()
,这是一个用于字符串的汇总函数。
14.3.1 str_c()
str_c()
接受任意数量的向量作为参数,并返回一个字符向量:
str_c()
与 R base 的 paste0()
非常相似,但它被设计为与 mutate()
一起使用,遵循了 tidyverse 的常规规则,即循环补齐和传播缺失值:
如果你希望缺失值以另一种方式显示,可以使用 coalesce()
来替换它们。根据你的需求,你可以在 str_c()
内部或外部使用它:
df |>
mutate(
greeting1 = str_c("Hi ", coalesce(name, "you"), "!"),
greeting2 = coalesce(str_c("Hi ", name, "!"), "Hi!")
)
#> # A tibble: 4 × 3
#> name greeting1 greeting2
#> <chr> <chr> <chr>
#> 1 Flora Hi Flora! Hi Flora!
#> 2 David Hi David! Hi David!
#> 3 Terra Hi Terra! Hi Terra!
#> 4 <NA> Hi you! Hi!
14.3.2 str_glue()
如果你用 str_c()
混合许多固定的和可变的字符串,你会注意到你输入了大量的 "
,这使得代码的整体目标难以看清。另一种方法是由 glue 包 通过 str_glue()
4 提供的。你给它一个具有特殊功能的单一字符串:{}
里的任何东西都会像在引号外面一样被求值:
如你所见,str_glue()
目前将缺失值转换为字符串 "NA"
,不幸的是,这与 str_c()
不一致。
你可能还会想,如果需要在字符串中包含一个常规的 {
或 }
,会发生什么。如果你猜到需要以某种方式转义它,那你的思路是正确的。诀窍在于 glue 使用了一种稍微不同的转义技术:不是用像 \
这样的特殊字符作为前缀,而是将特殊字符加倍:
14.3.3 str_flatten()
str_c()
和 str_glue()
与 mutate()
配合得很好,因为它们的输出与输入长度相同。如果你想要一个能与 summarize()
很好配合的函数,即一个总是返回单个字符串的东西呢?这就是 str_flatten()
5 的工作:它接受一个字符向量,并将向量的每个元素组合成一个单一的字符串:
str_flatten(c("x", "y", "z"))
#> [1] "xyz"
str_flatten(c("x", "y", "z"), ", ")
#> [1] "x, y, z"
str_flatten(c("x", "y", "z"), ", ", last = ", and ")
#> [1] "x, y, and z"
这使得它能与 summarize()
很好地配合工作:
df <- tribble(
~ name, ~ fruit,
"Carmen", "banana",
"Carmen", "apple",
"Marvin", "nectarine",
"Terence", "cantaloupe",
"Terence", "papaya",
"Terence", "mandarin"
)
df |>
group_by(name) |>
summarize(fruits = str_flatten(fruit, ", "))
#> # A tibble: 3 × 2
#> name fruits
#> <chr> <chr>
#> 1 Carmen banana, apple
#> 2 Marvin nectarine
#> 3 Terence cantaloupe, papaya, mandarin
14.3.4 练习
14.4 从字符串中提取数据
将多个变量塞进一个字符串中是很常见的。在本节中,你将学习如何使用四个 tidyr 函数来提取它们:
df |> separate_longer_delim(col, delim)
df |> separate_longer_position(col, width)
df |> separate_wider_delim(col, delim, names)
df |> separate_wider_position(col, widths)
如果你仔细观察,你会发现这里有一个共同的模式:separate_
,然后是 longer
或 wider
,然后是 _
,然后是 delim
或 position
。这是因为这四个函数是由两个更简单的原语组成的:
- 就像
pivot_longer()
和pivot_wider()
一样,_longer
函数通过创建新行来使输入的数据框变长,而_wider
函数通过生成新列来使输入的数据框变宽。 -
delim
用像", "
或" "
这样的分隔符来分割字符串;position
在指定的宽度处分割,比如c(3, 5, 2)
。
我们将在 Chapter 15 中回到这个家族的最后一个成员,separate_wider_regex()
。它是 wider
函数中最灵活的一个,但在使用它之前,你需要对正则表达式有所了解。
接下来的两节将为你介绍这些 separate
函数背后的基本思想,首先是分成行(这稍微简单一些),然后是分成列。最后,我们将讨论 wider
函数为你提供的诊断问题的工具。
14.4.1 分成行
当不同行中组件的数量不同时,将字符串分成行通常最有用。最常见的情况是需要 separate_longer_delim()
根据分隔符进行分割:
df1 <- tibble(x = c("a,b,c", "d,e", "f"))
df1 |>
separate_longer_delim(x, delim = ",")
#> # A tibble: 6 × 1
#> x
#> <chr>
#> 1 a
#> 2 b
#> 3 c
#> 4 d
#> 5 e
#> 6 f
separate_longer_position()
在实践中比较少见,但一些较老的数据集确实使用一种非常紧凑的格式,其中每个字符都用来记录一个值:
df2 <- tibble(x = c("1211", "131", "21"))
df2 |>
separate_longer_position(x, width = 1)
#> # A tibble: 9 × 1
#> x
#> <chr>
#> 1 1
#> 2 2
#> 3 1
#> 4 1
#> 5 1
#> 6 3
#> # ℹ 3 more rows
14.4.2 分成列
当每个字符串中都有固定数量的组件,并且你希望将它们分散到列中时,将字符串分成列通常最有用。它们比它们的 longer
等价物稍微复杂一些,因为你需要命名这些列。例如,在下面的数据集中,x
由一个代码、一个版本号和一个年份组成,用 .
分隔。要使用 separate_wider_delim()
,我们需要在两个参数中提供分隔符和名称:
df3 <- tibble(x = c("a10.1.2022", "b10.2.2011", "e15.1.2015"))
df3 |>
separate_wider_delim(
x,
delim = ".",
names = c("code", "edition", "year")
)
#> # A tibble: 3 × 3
#> code edition year
#> <chr> <chr> <chr>
#> 1 a10 1 2022
#> 2 b10 2 2011
#> 3 e15 1 2015
如果某个特定的部分没有用,你可以使用 NA
名称来从结果中省略它:
df3 |>
separate_wider_delim(
x,
delim = ".",
names = c("code", NA, "year")
)
#> # A tibble: 3 × 2
#> code year
#> <chr> <chr>
#> 1 a10 2022
#> 2 b10 2011
#> 3 e15 2015
separate_wider_position()
的工作方式略有不同,因为你通常需要指定每列的宽度。所以你给它一个命名的整数向量,其中名称给出新列的名称,值是它占用的字符数。你可以通过不命名来从输出中省略值:
df4 <- tibble(x = c("202215TX", "202122LA", "202325CA"))
df4 |>
separate_wider_position(
x,
widths = c(year = 4, age = 2, state = 2)
)
#> # A tibble: 3 × 3
#> year age state
#> <chr> <chr> <chr>
#> 1 2022 15 TX
#> 2 2021 22 LA
#> 3 2023 25 CA
14.4.3 诊断变宽问题
separate_wider_delim()
6 需要一个固定的、已知的列集合。如果某些行没有预期的片段数量,会发生什么?可能存在两种问题:片段太少或太多,所以 separate_wider_delim()
提供了两个参数来帮助解决:too_few
和 too_many
。我们首先用下面的示例数据集来看一下 too_few
的情况:
df <- tibble(x = c("1-1-1", "1-1-2", "1-3", "1-3-2", "1"))
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z")
)
#> Error in `separate_wider_delim()`:
#> ! Expected 3 pieces in each element of `x`.
#> ! 2 values were too short.
#> ℹ Use `too_few = "debug"` to diagnose the problem.
#> ℹ Use `too_few = "align_start"/"align_end"` to silence this message.
你会注意到我们得到了一个错误,但错误信息给了我们一些关于如何继续的建议。让我们从调试问题开始:
debug <- df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_few = "debug"
)
#> Warning: Debug mode activated: adding variables `x_ok`, `x_pieces`, and
#> `x_remainder`.
debug
#> # A tibble: 5 × 6
#> x y z x_ok x_pieces x_remainder
#> <chr> <chr> <chr> <lgl> <int> <chr>
#> 1 1-1-1 1 1 TRUE 3 ""
#> 2 1-1-2 1 2 TRUE 3 ""
#> 3 1-3 3 <NA> FALSE 2 ""
#> 4 1-3-2 3 2 TRUE 3 ""
#> 5 1 <NA> <NA> FALSE 1 ""
当你使用调试模式时,输出中会增加三列:x_ok
、x_pieces
和 x_remainder
(如果你分离一个不同名称的变量,你会得到一个不同的前缀)。在这里,x_ok
让你能够快速找到失败的输入:
debug |> filter(!x_ok)
#> # A tibble: 2 × 6
#> x y z x_ok x_pieces x_remainder
#> <chr> <chr> <chr> <lgl> <int> <chr>
#> 1 1-3 3 <NA> FALSE 2 ""
#> 2 1 <NA> <NA> FALSE 1 ""
x_pieces
告诉我们找到了多少个片段,而预期是 3 个(names
的长度)。当片段太少时,x_remainder
没有用,但我们很快会再次看到它。
有时,查看这些调试信息会揭示你的分隔符策略存在问题,或者表明你需要在分离前进行更多的预处理。在这种情况下,修复上游的问题,并确保移除 too_few = "debug"
,以确保新问题会变成错误。
在其他情况下,你可能希望用 NA
填充缺失的片段然后继续。这就是 too_few = "align_start"
和 too_few = "align_end"
的工作,它们允许你控制 NA
应该放在哪里:
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_few = "align_start"
)
#> # A tibble: 5 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 1 1
#> 2 1 1 2
#> 3 1 3 <NA>
#> 4 1 3 2
#> 5 1 <NA> <NA>
如果你有太多的片段,同样的原则也适用:
df <- tibble(x = c("1-1-1", "1-1-2", "1-3-5-6", "1-3-2", "1-3-5-7-9"))
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z")
)
#> Error in `separate_wider_delim()`:
#> ! Expected 3 pieces in each element of `x`.
#> ! 2 values were too long.
#> ℹ Use `too_many = "debug"` to diagnose the problem.
#> ℹ Use `too_many = "drop"/"merge"` to silence this message.
但是现在,当我们调试结果时,你可以看到 x_remainder
的用途:
debug <- df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_many = "debug"
)
#> Warning: Debug mode activated: adding variables `x_ok`, `x_pieces`, and
#> `x_remainder`.
debug |> filter(!x_ok)
#> # A tibble: 2 × 6
#> x y z x_ok x_pieces x_remainder
#> <chr> <chr> <chr> <lgl> <int> <chr>
#> 1 1-3-5-6 3 5 FALSE 4 -6
#> 2 1-3-5-7-9 3 5 FALSE 5 -7-9
对于处理过多的片段,你有一套略有不同的选项:你可以静默地“drop”(丢弃)任何额外的片段,或者将它们全部“merge”(合并)到最后一列:
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_many = "drop"
)
#> # A tibble: 5 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 1 1
#> 2 1 1 2
#> 3 1 3 5
#> 4 1 3 2
#> 5 1 3 5
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_many = "merge"
)
#> # A tibble: 5 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 1 1
#> 2 1 1 2
#> 3 1 3 5-6
#> 4 1 3 2
#> 5 1 3 5-7-9
14.5 字母
在本节中,我们将向你介绍一些函数,让你能够处理字符串中的单个字母。你将学习如何找到字符串的长度,提取子字符串,以及在图表和表格中处理长字符串。
14.5.1 长度
str_length()
告诉你字符串中有多少个字母:
str_length(c("a", "R for data science", NA))
#> [1] 1 18 NA
你可以将此与 count()
一起使用,以找出美国婴儿姓名长度的分布,然后用 filter()
查看最长的名字,这些名字恰好有 15 个字母7:
babynames |>
count(length = str_length(name), wt = n)
#> # A tibble: 14 × 2
#> length n
#> <int> <int>
#> 1 2 338150
#> 2 3 8589596
#> 3 4 48506739
#> 4 5 87011607
#> 5 6 90749404
#> 6 7 72120767
#> # ℹ 8 more rows
babynames |>
filter(str_length(name) == 15) |>
count(name, wt = n, sort = TRUE)
#> # A tibble: 34 × 2
#> name n
#> <chr> <int>
#> 1 Franciscojavier 123
#> 2 Christopherjohn 118
#> 3 Johnchristopher 118
#> 4 Christopherjame 108
#> 5 Christophermich 52
#> 6 Ryanchristopher 45
#> # ℹ 28 more rows
14.5.2 子集
你可以使用 str_sub(string, start, end)
来提取字符串的一部分,其中 start
和 end
是子字符串应该开始和结束的位置。start
和 end
参数是包含性的,所以返回的字符串长度将是 end - start + 1
:
你可以使用负值从字符串的末尾向前计数:-1 是最后一个字符,-2 是倒数第二个字符,依此类推。
str_sub(x, -3, -1)
#> [1] "ple" "ana" "ear"
请注意,如果字符串太短,str_sub()
不会失败:它只会返回尽可能多的内容:
str_sub("a", 1, 5)
#> [1] "a"
我们可以使用 str_sub()
和 mutate()
来找出每个名字的首字母和末尾字母:
babynames |>
mutate(
first = str_sub(name, 1, 1),
last = str_sub(name, -1, -1)
)
#> # A tibble: 1,924,665 × 7
#> year sex name n prop first last
#> <dbl> <chr> <chr> <int> <dbl> <chr> <chr>
#> 1 1880 F Mary 7065 0.0724 M y
#> 2 1880 F Anna 2604 0.0267 A a
#> 3 1880 F Emma 2003 0.0205 E a
#> 4 1880 F Elizabeth 1939 0.0199 E h
#> 5 1880 F Minnie 1746 0.0179 M e
#> 6 1880 F Margaret 1578 0.0162 M t
#> # ℹ 1,924,659 more rows
14.5.3 练习
- 在计算婴儿姓名长度的分布时,我们为什么使用
wt = n
? - 使用
str_length()
和str_sub()
从每个婴儿名字中提取中间的字母。如果字符串有偶数个字符,你该怎么办? - 婴儿姓名的长度随时间变化有任何主要趋势吗?首字母和末尾字母的流行度呢?
14.6 非英文文本
到目前为止,我们主要关注英文文本,处理英文文本特别容易,原因有二。首先,英文字母相对简单:只有 26 个字母。其次(也许更重要),我们今天使用的计算基础设施主要是由说英语的人设计的。不幸的是,我们没有足够的篇幅来全面处理非英文语言。尽管如此,我们还是想提醒你注意一些你可能会遇到的最大挑战:编码、字母变体和依赖于区域设置的函数。
14.6.1 编码
在处理非英文文本时,第一个挑战通常是编码 (encoding)。要理解发生了什么,我们需要深入了解计算机是如何表示字符串的。在 R 中,我们可以使用 charToRaw()
来获取字符串的底层表示:
charToRaw("Hadley")
#> [1] 48 61 64 6c 65 79
这六个十六进制数中的每一个都代表一个字母:48
是 H,61
是 a,依此类推。从十六进制数到字符的映射称为编码,在这种情况下,编码被称为 ASCII。ASCII 在表示英文字符方面做得很好,因为它是美国信息交换标准代码。
对于非英语语言来说,事情就没那么简单了。在计算的早期,有许多竞争性的标准用于编码非英文字符。例如,欧洲有两种不同的编码:Latin1(又名 ISO-8859-1)用于西欧语言,而 Latin2(又名 ISO-8859-2)用于中欧语言。在 Latin1 中,字节 b1
是 “±”,但在 Latin2 中,它是 “ą”!幸运的是,今天有一个几乎在任何地方都支持的标准:UTF-8。UTF-8 几乎可以编码当今人类使用的所有字符,以及许多额外的符号,如表情符号。
readr 处处使用 UTF-8。这是一个很好的默认设置,但对于由不使用 UTF-8 的旧系统产生的数据来说,这会失败。如果发生这种情况,你的字符串在打印时会看起来很奇怪。有时可能只有一两个字符出错;其他时候,你会得到完全的乱码。例如,这里是两个带有不寻常编码的内联 CSV8:
要正确读取这些内容,你需要通过 locale
参数指定编码:
你如何找到正确的编码?如果幸运的话,它会包含在数据文档的某个地方。不幸的是,这种情况很少见,所以 readr 提供了 guess_encoding()
来帮助你找出它。它不是万无一失的,并且在你有很多文本时效果更好(不像这里),但它是一个合理的起点。预计你需要尝试几种不同的编码才能找到正确的那个。
编码是一个丰富而复杂的主题;我们在这里只触及了皮毛。如果你想了解更多,我们建议阅读 http://kunststube.net/encoding/ 上的详细解释。
14.6.2 字母变体
在处理带重音的语言时,确定字母的位置(例如,使用 str_length()
和 str_sub()
)会带来一个重大挑战,因为带重音的字母可能被编码为单个独立的字符(例如,ü),或者通过组合一个不带重音的字母(例如,u)和一个变音符号(例如,¨)来编码为两个字符。例如,这段代码显示了两种看起来相同的 ü 的表示方法:
但这两个字符串的长度不同,并且它们的第一个字符也不同:
str_length(u)
#> [1] 1 2
str_sub(u, 1, 1)
#> [1] "ü" "u"
最后,请注意,使用 ==
比较这些字符串会将它们解释为不同的,而 stringr 中方便的 str_equal()
函数则能识别出它们俩具有相同的外观:
u[[1]] == u[[2]]
#> [1] FALSE
str_equal(u[[1]], u[[2]])
#> [1] TRUE
14.6.3 依赖于区域设置的函数
最后,还有一些 stringr 函数的行为取决于你的区域设置 (locale)。区域设置类似于一种语言,但包含一个可选的地区说明符,以处理一种语言内部的地区差异。区域设置由一个小写的语言缩写指定,后面可以选择性地跟一个 _
和一个大写的地区标识符。例如,“en” 是英语,“en_GB” 是英式英语,“en_US” 是美式英语。如果你还不知道你语言的代码,维基百科 有一个很好的列表,你可以通过查看 stringi::stri_locale_list()
来看看 stringr 支持哪些。
R base 的字符串函数会自动使用你的操作系统设置的区域设置。这意味着 R base 的字符串函数会按照你期望的方式对你的语言进行操作,但如果你的代码与生活在不同国家的人共享,它可能会有不同的表现。为了避免这个问题,stringr 默认使用 “en” 区域设置的英语规则,并要求你指定 locale
参数来覆盖它。幸运的是,只有两组函数的区域设置真正重要:改变大小写和排序。
改变大小写的规则在不同语言中有所不同。例如,土耳其语中有两个 i:带点和不带点的。由于它们是两个不同的字母,它们的大小写转换也不同:
str_to_upper(c("i", "ı"))
#> [1] "I" "I"
str_to_upper(c("i", "ı"), locale = "tr")
#> [1] "İ" "I"
对字符串进行排序取决于字母表的顺序,而字母表的顺序在每种语言中都不尽相同9!这里有一个例子:在捷克语中,“ch” 是一个复合字母,它在字母表中出现在 h
之后。
这在使用 dplyr::arrange()
对字符串进行排序时也会出现,这就是为什么它也有一个 locale
参数。
14.7 总结
在本章中,你已经了解了 stringr 包的一些强大功能:如何创建、组合和提取字符串,以及在处理非英语字符串时可能面临的一些挑战。现在是时候学习一个处理字符串最重要、最强大的工具之一了:正则表达式。正则表达式是一种非常简洁但表达能力极强的语言,用于描述字符串内的模式,它是下一章的主题。
或者使用 R base 函数
writeLines()
。↩︎R 4.0.0 及以上版本可用。↩︎
str_view()
还使用颜色来提请你注意制表符、空格、匹配项等。这些颜色目前在书中不显示,但你在交互式运行代码时会注意到它们。↩︎如果你没有使用 stringr,你也可以直接用
glue::glue()
来访问它。↩︎同样的原则也适用于
separate_wider_position()
和separate_wider_regex()
。↩︎查看这些条目,我们猜测 babynames 数据丢弃了空格或连字符,并在 15 个字母后截断。↩︎
在这里,我使用特殊的
\x
将二进制数据直接编码到字符串中。↩︎在没有字母表的语言(如中文)中排序则更为复杂。↩︎