如何用stringr::str_replace提取下划线分隔的第三个元素?
用str_replace提取下划线分隔字符串的第三个元素
嘿,我看你想用str_replace替代str_split来提取下划线分隔字符串里的第三个元素,不过你当前的正则因为贪婪匹配的问题没拿到正确结果,我来帮你修正下~
问题分析
你之前写的正则(.+)_(.+)_(.+)_*(.*)_*(.*)里,.+是贪婪匹配——它会尽可能多的吃掉字符,导致第一个.+直接吃到倒数第二个下划线的位置,最后捕获的\\3变成了字符串的最后一段(比如第一个例子里的feee),这就和你想要的结果背道而驰了。
修正方案
我们可以用明确匹配非下划线字符的方式来避免贪婪问题,正则写成:^[^_]+_[^_]+_([^_]+).*,然后用str_replace把整个字符串替换为捕获组\\1的内容,就能得到第三个元素了,同时也保留了分组。
测试代码及结果
library(tidyverse) library(stringr) # 构建测试数据 d <- enframe( c("asfe_01_AAAA_fses_feee", "asfe_87_BBBB_fses_feee", "99_fesf_CCCC_feee", "99_fesf_DDDD"), name = NULL, value = "txt" ) # 修正后的处理逻辑 d %>% mutate( x = str_replace(txt, "^[^_]+_[^_]+_([^_]+).*", "\\1"), want_strsplit = str_split(txt, "_", simplify = TRUE)[, 3] )
运行后得到的结果和预期一致:
| txt | x | want_strsplit |
|---|---|---|
| asfe_01_AAAA_fses_feee | AAAA | AAAA |
| asfe_87_BBBB_fses_feee | BBBB | BBBB |
| 99_fesf_CCCC_feee | CCCC | CCCC |
| 99_fesf_DDDD | DDDD | DDDD |
正则解释
拆解一下这个正则的各个部分:
^:锚定字符串开头,确保从最开始匹配,避免中间匹配的干扰[^_]+:匹配任意不是下划线的字符(至少一个),刚好对应下划线分隔的单个元素[^_]+_:匹配第一个元素加上后面的下划线分隔符- 重复一次
[^_]+_,就完成了第二个元素和后续下划线的匹配 ([^_]+):这是我们的捕获组,专门匹配第三个元素(所有非下划线字符),后续用\\1调用这个组的内容.*:匹配第三个元素之后的所有内容(不管有没有下划线,全部匹配掉)
这样str_replace就会把整个字符串替换成我们需要的第三个元素,和str_split的结果完全同步~
内容的提问来源于stack exchange,提问作者r.user.05apr
相关产品推荐
相关产品推荐

