我正在尝试使用正则表达式提取数据框中的部分列。我遇到的问题包括grep
返回整个值的事实,而不仅仅是匹配的部分,str_extract
似乎没有以矢量化的方式工作。
这是我正在尝试的。我希望df$match
显示模式存在的alpha.alpha.
,否则显示NA
。如何只显示匹配的部分?
另外,我如何在R regex中替换[a-zA-Z]
?我可以使用像[:alpha:]
这样的字符类或POSIX代码吗?
v1 <- c(1:4)
v2 <- c("_a.b._", NA, "_C.D._", "_ef_")
df <- data.frame(v1, v2, stringsAsFactors = FALSE)
df$match <- grepl("[a-zA-Z]\\.[a-zA-Z]\\.", df$v2)
df$match
#TRUE FALSE TRUE FALSE
v2grep <- grep("[a-zA-Z]\\.[a-zA-Z]\\.", df$v2, value = TRUE)
df$match[df$match == TRUE] <- v2grep
df$match[df$match == FALSE] <- NA
df
#v1 v2 match
#1 _a.b._ _a.b._
#2 <NA> <NA>
#3 _C.D._ _C.D._
#4 _ef_ <NA>
我想要的是什么:
#v1 v2 match
#1 _a.b._ a.b.
#2 <NA> <NA>
#3 _C.D._ C.D.
#4 _ef_ <NA>
答案 0 :(得分:4)
4方法......
这里有2种基本方法,以及我维护的 qdapRegex 包中的rm_default(extract=TRUE)
和 stringi 包。
unlist(sapply(regmatches(df[["v2"]], gregexpr("[a-zA-Z]\\.[a-zA-Z]\\.", df[["v2"]])), function(x){
ifelse(identical(character(0), x), NA, x)
})
)
## [1] "a.b." NA "C.D." NA
pat <- "(.*?)([a-zA-Z]\\.[a-zA-Z]\\.)(.*?)$"
df[["v2"]][!grepl(pat, df[["v2"]])] <- NA
df[["v2"]] <- gsub(pat, "\\2", df[["v2"]])
## [1] "a.b." NA "C.D." NA
library(qdapRegex)
unlist(rm_default(df[["v2"]], pattern = "[a-zA-Z]\\.[a-zA-Z]\\.", extract = TRUE))
## [1] "a.b." NA "C.D." NA
library(stringi)
stri_extract_first_regex(df[["v2"]], "[a-zA-Z]\\.[a-zA-Z]\\.")
## [1] "a.b." NA "C.D." NA
答案 1 :(得分:4)
使用regmatches
的基础R解决方案,如果未找到正则表达式匹配,则regexpr
返回-1
:
r <- regexpr("[a-zA-Z]\\.[a-zA-Z]\\.", df$v2)
df$match <- NA
df$match[which(r != -1)] <- regmatches(df$v2, r)
# v1 v2 match
#1 1 _a.b._ a.b.
#2 2 <NA> <NA>
#3 3 _C.D._ C.D.
#4 4 _ef_ <NA>
答案 2 :(得分:3)
使用grepl
和sub
的一种可能解决方案:
# First, remove unwanted characters around pattern when detected
df$match <- sub(pattern = ".*([a-zA-Z]\\.[a-zA-Z]\\.).*",
replacement = "\\1", x = df$v2)
# Second, check if pattern is present; otherwise set to NA
df$match <- ifelse(grepl(pattern = "[a-zA-Z]\\.[a-zA-Z]\\.", x = df$match),
yes = df$match, no = NA)
<强>结果
df
# v1 v2 match
# 1 1 _a.b._ a.b.
# 2 2 <NA> <NA>
# 3 3 _C.D._ C.D.
# 4 4 _ef_ <NA>
数据强>
v1 <- c(1:4)
v2 <- c("_a.b._", NA, "_C.D._", "_ef_")
df <- data.frame(v1, v2, stringsAsFactors = FALSE)