示例:
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
。
答案 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()
。