在 R 中创建字符串
R 中的字符串就是引号之间的文本。双引号和单引号都可以用,含义完全相同;惯例是用双引号,当文本本身包含双引号时再改用单引号:
反斜杠转义和大多数语言一样:\" 表示字面的引号,\n 表示换行,\t 表示制表符,\\ 表示反斜杠本身。
接下来是每个 R 初学者都会犯一次的错误:用 length() 去问字符串有多长。
nchar() 统计的是字符,结果是 5。length() 统计的是向量元素,而单个字符串是只有一个元素的向量,所以结果是 1。在 R 中一切都是向量,文本也不例外,本页所有函数都会悄悄地对整个字符向量逐元素运算。等你不再为此感到意外,就会发现这是个好特性。
拼接字符串:paste() 和 paste0()
R 没有用于字符串的 +。拼接用 paste(),它默认用空格连接各个参数;还有 paste0(),它直接相连,不加分隔符:
由于 paste 是向量化的,传给它一个向量就能一次生成多个字符串,一行代码就能生成文件名、标签和 ID:
collapse 参数的作用正好相反:它用指定的分隔符把整个向量合并成一个字符串:
记住两者的分工:sep 控制参数之间的连接符,collapse 控制同一个向量的元素之间的连接符。两者可以在同一次调用中同时使用。
用 sprintf() 格式化
当你需要在文本中格式化数字,比如固定小数位数或补齐宽度时,paste() 就力不从心了,这时轮到 sprintf() 登场。它使用 C 风格的格式码:%s 表示字符串,%d 表示整数,%f 表示小数:
%.1f 表示“保留一位小数”,%.3f 表示三位,%05d 表示用 0 补齐到五位数字。连写两个 %% 会输出一个字面的百分号。sprintf() 同样是向量化的,一次调用就能格式化一整列值。sprintf() + cat() 的报告写法请参阅输入和输出。
大小写转换与截取:toupper()、tolower()、substr()
大小写转换正如其名:
tolower() 的用武之地是在比较之前规范化杂乱的数据:"Yes"、"YES" 和 "yes" 都会变成同一个值。
substr(x, start, stop) 按字符位置截取一段,从 1 开始计数(R 在任何地方都从 1 开始索引):
两端都包含在内:位置 1 到 11 得到 "Programming"。
查找与替换:sub()、gsub() 和 grepl()
sub() 替换模式的第一个匹配;gsub()(“global substitute”,全局替换)替换所有匹配:
有一个关键细节:模式默认是正则表达式,而不是字面文本。.、*、( 和 ? 等正则字符都有特殊含义,单独一个 . 会匹配任意字符。如果你要匹配字面文本,就传入 fixed = TRUE:
第一行得到 a-b-c;第二行得到 -----,因为作为正则表达式,. 匹配了每一个字符。在学会正则表达式之前,把 fixed = TRUE 当作默认写法,就永远不会踩坑。
grepl() 不做替换,它检测每个元素是否匹配,返回一个逻辑向量。这让它成为筛选文本的标准工具:
第一个结果标出哪些文件名包含 .csv;第二个用这个逻辑向量只保留匹配的元素。
拆分与去空格:strsplit() 和 trimws()
strsplit() 按分隔符把字符串切开。它有一个特别之处:返回的是一个列表,因为它可以一次拆分多个字符串。对单个字符串,用 [[1]] 取出第一个元素:
trimws() 则会去掉真实数据中总是包裹在两边的空白:
默认两端都去除;which = "left" 或 "right" 只去除一侧(这里的左右指字符串的开头和结尾)。
另一种选择:stringr
上面的内容都是基础 R:随时可用,无需安装。tidyverse 的 stringr 包把同样的操作封装成统一的 str_* 命名方式,并且字符串总是第一个参数,很多人觉得这样更容易记(安装方法见包):
library(stringr)
str_detect(files, "csv") # like grepl(), data first
str_replace_all(s, "good", "great") # like gsub(), arguments reordered
str_length("hello") # like nchar()
无论如何,基础 R 的字符串函数都值得掌握:你会在每一个脚本、每一个 Stack Overflow 回答和每一条错误信息里遇到它们。先学基础函数名;等参数顺序不统一开始让你烦恼时,再换用 stringr。
本节要点
- 字符串惯例上用双引号;
nchar()统计字符数,length()统计向量元素数。 - 用
paste()/paste0()拼接;sep连接各个参数,collapse把一个向量合并成一个字符串。 sprintf()负责格式化输出:%s、%d、%.2f。sub()替换第一个匹配,gsub()替换所有匹配,grepl()检测是否匹配;它们默认都按正则表达式处理,要匹配字面文本就传入fixed = TRUE。strsplit()返回列表(用[[1]]取出);trimws()清理两侧带空格的输入。
下一节:让文本进出你的程序,用 print() 和 cat() 打印,以及读取用户输入。
常见问题
R 中如何拼接字符串?
用 paste() 或 paste0(),R 没有用于字符串的 +。paste("data", "science") 得到 "data science"(默认用空格分隔);paste0("data", "science") 则直接相连。用 sep = 修改分隔符,用 collapse = 把整个向量合并成一个字符串。
R 中如何获取字符串的长度?
nchar("hello") 返回 5,即字符个数。length("hello") 返回 1:在 R 中,length() 统计的是向量的元素个数,而单个字符串就是只有一个元素的向量。把 length() 和 nchar() 搞混是初学者的经典错误。
R 中 sub() 和 gsub() 有什么区别?
两者都能查找并替换,但 sub() 只替换第一个匹配,而 gsub()(“global sub”,全局替换)替换所有匹配。两者默认都把模式当作正则表达式;传入 fixed = TRUE 则按字面文本匹配。
R 中如何拆分字符串?
strsplit(x, split) 按模式拆分字符串,但它返回的是一个列表(因为它可以一次拆分多个字符串)。对单个字符串,取出第一个元素即可:strsplit("a,b,c", ",")[[1]] 得到字符向量 "a" "b" "c"。