从字符串末尾分隔定界符固定次数

时间:2016-01-18 15:31:26

标签: 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(lengths(strsplit(df$strings, "_")))max(lengths(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

我已经尝试了很多正则表达式,我已经非常绝望......

2 个答案:

答案 0 :(得分:5)

以下是一些可能的解决方案:

1)gsubfn包中的read.pattern read.pattern可以直接生成数据帧结果。没有使用其他包。它使用了一个特别简单的正则表达式。

首先我们创建模式pat。例如,如果k3,则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)

,并提供:

                   V1     V2    V3
1                ooss   bboo   foo
2                  ee bbbbee fffee
3             aas_baa   ffaa   daa
4 iisss_bbbbii_ffffii    dii   mii

2)sub / read.table 。相对于先前的解决方案,该解决方案涉及额外的步骤(sub / repl部分);但是,它根本不使用任何包。它使用了上面的stringskpat。如果k等于3,则repl的值为"\\1,\\2,\\3"

repl <- paste(paste0("\\", 1:k), collapse = ",")
read.table(text = sub(pat, repl, strings), sep = ",", as.is = TRUE)

给出相同的结果。 ","的两个实例可以替换为数据中未找到的任何字符。

注意:在上面的解决方案中,我们使用as.is = TRUE来使输出列成为字符,但如果因子是正确的则可以省略此参数。

答案 1 :(得分:3)

我已经假装了一支蛮力的&#34; stringi版本。由于OP决定添加颜色评论,所以在接受的答案和这个答案之间进行比较(我在删除的评论中错了,我的速度比#34更少;但是更少但仍然是额外的包&#34 ;回答,如果那种事情对人们很重要):

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)

enter image description here