Regex 从字符串末尾拆分分隔符的次数固定
我有一个数据框,如下所示:Regex 从字符串末尾拆分分隔符的次数固定,regex,r,Regex,R,我有一个数据框,如下所示: df = data.frame(a = 1:4, strings = c('ooss_bboo_foo','ee_bbbbee_fffee','aas_baa_ffaa_daa', 'iisss_bbbbii_ffffii_dii_mii')) 我想在上拆分,生成新的列(或新的数据帧,其实并不重要)。可以使用min(长度(strsplit(df$strings,“”))和max(长度(strsplit(df$strings,“”)) 期望输出: X1
df = data.frame(a = 1:4, strings = c('ooss_bboo_foo','ee_bbbbee_fffee','aas_baa_ffaa_daa', 'iisss_bbbbii_ffffii_dii_mii'))
我想在上拆分,生成新的列(或新的数据帧,其实并不重要)。可以使用min(长度(strsplit(df$strings,“”))
和max(长度(strsplit(df$strings,“”))
期望输出:
X1 X2 X3
1 ooss bboo foo
2 ee bbbbee fffee
3 aas_baa ffaa daa
4 iisss_bbbbii_ffffii dii mii
我已经尝试了大量的正则表达式,我已经非常绝望了…以下是一些可能的解决方案:
1)gsubfn包中的read.patternread.pattern
可以直接生成数据帧结果。没有使用其他软件包。它使用一个特别简单的正则表达式
首先,我们创建模式,pat
。例如,如果k
是3
,那么pat
是“(.*)_(.*)_(.*)”
。然后,只需运行read.pattern
即可生成结果data.frame:
library(gsubfn)
strings <- as.character(df$strings) # ensure it's character, not factor
k <- min(lengths(strsplit(strings, "_"))) # from question
pat <- paste(rep("(.*)", k), collapse = "_")
read.pattern(text = strings, pattern = pat, as.is = TRUE)
2)子/读取表格。相对于先前的解决方案,该解决方案涉及一个额外的步骤(sub
/repl
部分);但是,它根本不使用包。它使用上面的字符串
、k
和pat
。如果k
等于3,repl
的值将是“\\1,\\2,\\3”
repl我提出了一个“蛮力”版本。由于OP决定添加彩色评论,下面是接受答案与此答案之间的比较(我删除的评论是错误的,我的答案比“更少但仍然额外”的答案快,如果这类事情对人们很重要的话):
库(stringi)
图书馆(magrittr)
图书馆(purrr)
图书馆(gsubfn)
图书馆(GG2)
图书馆(微基准)
df%
地图测向(功能(x){
数据帧(rbind(版本(stri_reverse(x))),stringsAsFactors=FALSE)
})
}
gsubfn_split_fixed_right你介意详细解释一下为什么它从结尾而不是从开头分开吗?是模式中的技巧
还是读取模式
?正则表达式是贪婪的,所以第一个*
会尽可能地吞掉所有东西。这种情况总是如此,不仅仅是在read.pattern
中。其关键字是回溯:)添加了第二个解决方案。+100用于此用例的read.table
版本。它比其他两个调用要快得多。do.call('rbind',strsplit(as.character(df$strings),'(?=[a-z]+$)(?=[a-z]+.[a-z]+$),perl=TRUE))
V1 V2 V3
1 ooss bboo foo
2 ee bbbbee fffee
3 aas_baa ffaa daa
4 iisss_bbbbii_ffffii dii mii
repl <- paste(paste0("\\", 1:k), collapse = ",")
read.table(text = sub(pat, repl, strings), sep = ",", as.is = TRUE)
library(stringi)
library(magrittr)
library(purrr)
library(gsubfn)
library(ggplot2)
library(microbenchmark)
df <- data.frame(a=1:4,
strings=c('ooss_bboo_foo',
'ee_bbbbee_fffee',
'aas_baa_ffaa_daa',
'iisss_bbbbii_ffffii_dii_mii'))
str_split_right_fixed <- function(str, pat, n) {
stri_reverse(df$strings) %>%
stri_split_fixed(pat, n) %>%
map_df(function(x) {
data.frame(rbind(rev(stri_reverse(x))), stringsAsFactors=FALSE)
})
}
gsubfn_split_fixed_right <- function(str, pat, n) {
pat <- paste(rep("(.*)", n), collapse = pat)
read.pattern(text = as.character(str), pattern = pat)
}
tab_split_fixed_right <- function(str, pat, n) {
repl <- paste(paste0("\\", 1:n), collapse = ",")
read.table(text = sub(pat, repl, str), sep = ",")
}
microbenchmark(str=str_split_right_fixed(df$strings, "_", 3),
gsb=gsubfn_split_fixed_right(df$strings, "_", 3),
tab=tab_split_fixed_right(df$strings, "_", 3),
times=1000) -> mb
autoplot(mb)