如何通过正则表达式拆分数据框中的列?

时间:2015-04-09 16:17:25

标签: regex r

示例:

ID <- c(1:5)
v1 <- c("abc1", "d2", "eF34", "GHi567", "NoNumber")
df <- data.frame(ID, v1, stringsAsFactors = FALSE)

我想做类似以下的事情,但是代码更简单,可能还有一个功能。 str_match_all中的stringr会很好,但需要原子矢量。我想我可以写一个循环,但我想要一些已经向量化的东西。 stringi中的某些内容会在这里有用吗?

pattern1 <- "([A-Za-z]+)([0-9]+)"
df$v2 <- sub(pattern = pattern1, replacement = "\\1", x = df$v1)
df$v3 <- sub(pattern = pattern1, replacement = "\\2", x = df$v1)

此外,我希望能够处理第5行中的匹配问题,制作df$v3[5] <- NA

3 个答案:

答案 0 :(得分:2)

一种选择是通过将strsplit指定为模式来拆分字符串(lookaround),并使用stri_list2matrix中的stringi将'list'输出转换为'matrix' 。这将填充NA以列出长度小于最大列表元素长度的元素。

library(stringi)
df[paste0('v', 2:3)] <- stri_list2matrix(strsplit(df$v1,
                  '(?<=[A-Za-z])(?=[0-9])', perl=TRUE), byrow=TRUE)

 df
 #  ID       v1       v2   v3
 #1  1     abc1      abc    1
 #2  2       d2        d    2
 #3  3     eF34       eF   34
 #4  4   GHi567      GHi  567
 #5  5 NoNumber NoNumber <NA>

或使用extract中的tidyr。我们paste可以NA最后没有数字元素的字符串并使用extract。这也可以通过指定convert=TRUE来转换'class'。

library(tidyr)
df$v1 <- with(df, ifelse(grepl('\\d+$', v1),v1, paste0(v1,NA)) )
extract(df, v1, into=c('v2', 'v3'), '([A-Za-z]+)([0-9]+|NA)', 
             remove=FALSE, convert=TRUE)
#   ID         v1       v2  v3
#1  1       abc1      abc   1
#2  2         d2        d   2
#3  3       eF34       eF  34
#4  4     GHi567      GHi 567
#5  5 NoNumberNA NoNumber  NA

base R选项

df[paste0('v', 2:3)] <- read.table(text=gsub('([A-Za-z]*)([0-9]*)',
    '\\1 \\2', df$v1), header=FALSE, stringsAsFactors=FALSE, fill=TRUE)

答案 1 :(得分:2)

轻微修改模式并使用as.numeric强制到正确的类:

pattern1 <- "([A-Za-z]+)([0-9]*)"
df$v2 <- sub(pattern = pattern1, replacement = "\\1", x = df$v1)
 df$v3 <- as.numeric(sub(pattern = pattern1, replacement = "\\2", x = df$v1))
 df

  ID       v1       v2  v3
1  1     abc1      abc   1
2  2       d2        d   2
3  3     eF34      eF4  34
4  4   GHi567    GHi67 567
5  5 NoNumber NoNumber  NA

答案 2 :(得分:2)

使用development version of data.table, v1.9.5

require(data.table) #v1.9.5
setDT(df)[, c("c1", "c2") := tstrsplit(v1, "(?<=[[:alpha:]])(?=[0-9])", perl=TRUE)]
#    ID       v1       c1  c2
# 1:  1     abc1      abc   1
# 2:  2       d2        d   2
# 3:  3     eF34       eF  34
# 4:  4   GHi567      GHi 567
# 5:  5 NoNumber NoNumber  NA

正则表达式从@akrun借来。如果您希望在type.convert=TRUE期间自动将c2转换为数字,请使用tstrsplit()