Menu

R 字符串:paste、sprintf、gsub、substr 等用法

在 R 中处理文本所需的一切:创建字符串,用 paste 和 paste0 拼接,用 sprintf 格式化,用 gsub、grepl 和 strsplit 查找与拆分。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

在 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"。

Coddy 编程语言插图

和 Coddy 一起学编程

开始