资讯详情

R 字符串处理完全指南:从基础操作到正则实战

📅 2026/11/2 1:49:05 | 华诺云谱 👁 阅读
R 字符串处理完全指南:从基础操作到正则实战
一、为什么 R 的字符串处理值得单独讲在数据分析的日常工作中字符串处理出现的频率远比想象中高清洗问卷里的自由文本、解析日志文件、从文件名中提取日期、把变量名拼成公式、给图表批量生成标题……这些任务都离不开字符串。R 的字符串能力由两部分组成一部分是 base R 自带的函数另一部分是stringr包提供的统一接口。前者无需安装、随处可用后者命名规范、参数一致适合处理复杂场景。本文会同时覆盖两者并在每个知识点上给出可直接运行的代码。本文所有示例基于 R 4.3 及以上版本stringr版本为 1.5.x。示例中的中文文本默认使用 UTF-8 编码。二、字符串的创建与基本属性2.1 创建字符串R 中没有单独的字符类型单个字符串本质上就是长度为 1 的字符向量。用单引号或双引号都可以创建两者在 R 中完全等价。s1 - hello s2 - world s3 - 包含中文的字符串 单双引号等价但内部含引号时需要转义或换用另一种引号 s4 - He said: R is great s5 - He said: R is great print(s4) print(s5)2.2 字符向量与长度需要特别注意length()返回的是向量中元素的个数而不是单个字符串的字符数。要获取字符数应使用nchar()。x - c(apple, banana, cherry) length(x) # 3向量中有 3 个元素 nchar(x) # 6 6 6每个字符串的字符数 nchar(数据分析) # 4中文按字符计数 按字节计数中文在 UTF-8 下通常占 3 字节 nchar(数据分析, type bytes)2.3 缺失值与空字符串NA表示缺失表示空字符串两者语义完全不同判断方式也不同。v - c(a, , NA) is.na(v) # FALSE FALSE TRUE v # FALSE TRUE NA nchar(v) # 1 0 NA 安全判断空字符串 is_empty - function(x) !is.na(x) nchar(x) 0 is_empty(v) # FALSE TRUE FALSE三、字符串拼接与拆分3.1 拼接paste 与 paste0paste()默认用空格连接paste0()等价于sep 是拼接时最常用的写法。paste(R, 语言) # R 语言 paste0(R, 语言) # R语言 paste(a, b, c, sep -) # a-b-c 向量化拼接长度不同时会自动循环补齐 paste0(第, 1:3, 章) 第1章 第2章 第3章 collapse 把整个向量压成一个字符串 paste(c(A, B, C), collapse , ) A, B, C3.2 拆分strsplitpath - 2024-05-18_report_final.csv parts - strsplit(path, [-_.])[[1]] print(parts) 2024 05 18 report final csv 注意 strsplit 返回的是 list即使输入只有一个元素 class(strsplit(path, _)) # list 批量拆分 files - c(a_1.txt, b_2.txt) strsplit(files, _) [[1]] a 1.txt [[2]] b 2.txt3.3 stringr 的对应写法library(stringr) str_c(R, 语言, sep ) # R 语言 str_c(第, 1:3, 章) # 第1章 第2章 第3章 str_c(c(A, B, C), collapse , ) # A, B, C str_split(path, [-.])[[1]] str_split_fixed(path, , n 2) # 返回矩阵固定列数四、子串提取与替换4.1 按位置截取s - abcdefgh substr(s, 1, 3) # abc substr(s, 4, 6) # def substring(s, 3) # cdefgh从第 3 位到末尾 向量化截取 substr(c(apple, banana), 1, 2) # ap ba stringr 写法参数顺序更直观 str_sub(s, 1, 3) # abc str_sub(s, -3, -1) # fgh负数表示从末尾计数4.2 替换子串sub()只替换第一个匹配gsub()替换全部匹配这是初学者最容易踩坑的地方。text - cat cat cat sub(cat, dog, text) # dog cat cat gsub(cat, dog, text) # dog dog dog 删除特定字符替换为空串 gsub(-, , 2024-05-18) # 20240518 stringr 对应函数 str_replace(text, cat, dog) # 只替换第一个 str_replace_all(text, cat, dog) # 替换全部4.3 大小写转换toupper(hello R) # HELLO R tolower(HELLO R) # hello r 首字母大写base R 无内置函数可自行实现 simple_cap - function(x) { paste0(toupper(substr(x, 1, 1)), tolower(substr(x, 2, nchar(x)))) } simple_cap(hello world) # Hello world stringr 提供 str_to_title str_to_title(hello world) # Hello World str_to_sentence(hello world) # Hello world五、空白处理与填充数据清洗中前后空格是最常见的脏数据来源之一。s - hello world trimws(s) # hello world trimws(s, which left) # hello world trimws(s, which right) # hello world stringr 版本 str_trim(s) # 去两端 str_trim(s, side left) # 只去左侧 str_squish( a b c ) # a b c同时压缩中间多余空格填充在生成固定宽度报表或对齐输出时很有用str_pad(7, width 3, pad 0) # 007 str_pad(7, width 3, side right) # 7 str_pad(R, width 5, pad *) # ****R六、字符串匹配与查找6.1 是否包含与位置查找s - c(apple, banana, cherry) grepl(an, s) # FALSE TRUE FALSE返回逻辑向量 grep(an, s) # 2返回匹配元素的下标 grep(an, s, value TRUE) # banana返回匹配的值 查找子串位置 regexpr(an, banana) # 2第一个匹配的起始位置 gregexpr(an, banana) # 2 4所有匹配位置 stringr 写法 str_detect(s, an) # FALSE TRUE FALSE str_which(s, an) # 2 str_subset(s, an) # banana str_locate(banana, an) # 起始 2结束 36.2 开头与结尾匹配files - c(report_2024.csv, data_2024.csv, report_2023.xlsx) 以 report 开头 str_starts(files, report) # TRUE FALSE TRUE 以 csv 结尾 str_ends(files, csv) # TRUE TRUE FALSE 组合筛选 files[str_starts(files, report) str_ends(files, csv)] report_2024.csv七、正则表达式实战R 的正则默认使用 POSIX 扩展语法stringr则基于 ICU 引擎支持更完整的语法。下面用几个真实场景说明。7.1 提取数字与日期library(stringr) log_line - 2024-05-18 10:23:45 ERROR user_id1024 cost3.5s 提取所有数字 str_extract_all(log_line, \d)[[1]] 2024 05 18 10 23 45 1024 3 5 提取日期 str_extract(log_line, \d{4}-\d{2}-\d{2}) # 2024-05-18 提取键值对中的值 str_extract(log_line, (?user_id)\d) # 1024后行断言 str_extract(log_line, (?cost)[0-9.]) # 3.57.2 分组捕获与替换# 把 yyyy-mm-dd 转成 dd/mm/yyyy date_str - 2024-05-18 str_replace(date_str, (\\d{4})-(\\d{2})-(\\d{2}), \\3/\\2/\\1) # 18/05/2024 批量处理 dates - c(2024-01-02, 2023-12-31) str_replace(dates, (\d{4})-(\d{2})-(\d{2}), \3/\2/\1) 02/01/2024 31/12/2023 用 gsub 实现同样效果 gsub((\d{4})-(\d{2})-(\d{2}), \3/\2/\1, dates)7.3 清洗不规范文本raw - c( 张三 , 李四(销售部), 王五 - 技术部 , NA) clean - raw | str_trim() | str_remove(\s*-\s*.$) | str_remove(\(.\)$) print(clean) 张三 李四 王五 NA 只保留中文字符 mixed - c(订单号A123, 客户B456) str_extract_all(mixed, [\u4e00-\u9fa5]) [[1]] 订单号 [[2]] 客户7.4 常用正则速查模式含义示例\\d数字\\d{3}匹配三位数字\\w字母、数字、下划线\\w匹配标识符\\s空白字符\\s匹配连续空格.任意字符不含换行a.c匹配 abc^/$行首 / 行尾^R以 R 开头[abc]字符集合[aeiou]匹配元音*?0 次以上 / 1 次以上 / 0 或 1 次a至少一个 a(?x)后行断言(?id)\\d八、格式化输出sprintf 与 glue拼接字符串时paste0在变量多的情况下可读性很差sprintf()和glue包是更好的选择。name - 张三 score - 92.456 sprintf(学生 %s 的得分为 %.1f, name, score) 学生 张三 的得分为 92.5 sprintf(%05d, 42) # 00042 sprintf(%.2f%%, 0.875) # 0.88% glue 包直接在字符串中嵌入表达式 library(glue) glue(学生 {name} 的得分为 {round(score, 1)}) 学生 张三 的得分为 92.5 循环生成标题 for (i in 1:3) { print(glue(第 {i} 季度销售额{i * 100} 万元)) }九、编码问题与中文处理中文乱码是 R 字符串处理中最常见的坑根源通常是文件编码与读取时声明的编码不一致。# 查看当前会话编码 Sys.getlocale(LC_CTYPE) 读取时显式指定编码 df - read.csv(data.csv, fileEncoding UTF-8) 编码转换 x - 中文 iconv(x, from UTF-8, to GBK) iconv(x, from GBK, to UTF-8) 检测非法编码返回 NA 表示无法转换 iconv(中文, from UTF-8, to ASCII, sub NA) 用 sub 参数替换无法转换的字符 iconv(中文abc, from UTF-8, to ASCII, sub ?) ??abc实践建议统一在项目中使用 UTF-8读取外部文件时始终显式声明fileEncoding避免依赖系统默认编码。十、综合案例清洗一份用户信息表下面把前面用到的技巧串起来完成一个贴近真实工作的清洗流程。library(stringr) users - data.frame( id 1:5, raw c( 张三 | 销售部 | 138-0000-1111 , 李四|技术部|139-0000-2222, 王五 | 财务部 | 137-0000-3333, 赵六|市场部|136-0000-4444, NA ), stringsAsFactors FALSE ) clean_users - users | transform( name str_trim(str_split_fixed(raw, \|, 3)[, 1]), dept str_trim(str_split_fixed(raw, \|, 3)[, 2]), phone str_remove_all(str_split_fixed(raw, \|, 3)[, 3], -) ) print(clean_users[, c(id, name, dept, phone)])输出结果中姓名与部门的前后空格被清除手机号中的连字符被移除缺失行保持NA而不会报错。这个流程可以进一步封装成函数复用到其他类似表格上。十一、性能与选型建议简单拼接与截取优先用 base R 的paste0、substr无需额外依赖。复杂正则与批量清洗优先用stringr函数命名统一str_前缀便于记忆且对NA的处理更一致。超大规模文本考虑stringi包stringr底层即基于它直接调用可减少一层封装开销。避免在循环中反复拼接用向量化函数一次性处理或预先分配向量再赋值。正则尽量具体用\\d而不是.可显著减少回溯带来的性能损耗。十二、小结R 的字符串处理能力可以概括为三层base R 提供基础能力stringr提供一致的接口stringi提供底层性能。掌握拼接、拆分、截取、替换、匹配这五类操作再配合正则表达式绝大多数文本清洗任务都能在几行代码内完成。建议读者把本文的代码复制到 RStudio 中逐段运行尤其是正则部分配合str_view()观察匹配结果理解会快很多。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑