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.pattern
read.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)