如何防止regmatches删除非匹配项?

16
我想要捕获第一个匹配项,如果没有匹配项则返回NA
regexpr("a+", c("abc", "def", "cba a", "aa"), perl=TRUE)
# [1]  1 -1  3  1
# attr(,"match.length")
# [1]  1 -1  1  2

x <- c("abc", "def", "cba a", "aa")
m <- regexpr("a+", x, perl=TRUE)
regmatches(x, m)
# [1]  "a"  "a"  "aa"

所以我期望的是 "a"、NA、"a"、"aa"


我原以为你要求的是第一个匹配项或者NA,但现在似乎有些混淆了。这凸显了提问时需要更高的准确性,最好附带请求的确切输出。 - IRTFM
5个回答

18

regexpr 保持一致:

r <- regexpr("a+", x)
out <- rep(NA,length(x))
out[r!=-1] <- regmatches(x, r)
out
#[1] "a"  NA   "a"  "aa"

14

使用regexec代替,因为它返回一个列表,这将允许您在unlist之前捕获character(0)

 R <- regmatches(x, regexec("a+", x))
 unlist({R[sapply(R, length)==0] <- NA; R})

 # [1] "a"  NA   "a"  "aa"

2
现在使用unlist({R[lengths(R)==0] <- NA; R})也可以了,因为最近的R版本中引入了lengths()函数。 - thelatemail

7
在R 3.3.0版本中,使用invert=NA参数可以同时提取匹配和非匹配结果。从帮助文件中可以看到,如果invert为NA,则regmatches提取非匹配和匹配子字符串,始终以非匹配开头和结尾(如果匹配发生在开头或结尾,则为空)。输出是一个列表,在大多数情况下(匹配单个模式),具有此参数的regmatches将返回一个元素长度为3或1的列表。1表示未找到匹配项,3表示找到匹配项的情况。
myMatch <- regmatches(x, m, invert=NA)
myMatch
[[1]]
[1] ""   "a"  "bc"

[[2]]
[1] "def"

[[3]]
[1] "cb" "a"  " a"

[[4]]
[1] ""   "aa" ""

所以要提取你想要的内容(将NA替换为""),可以使用sapply,如下所示:

myVec <- sapply(myMatch, function(x) {if(length(x) == 1) "" else x[2]})
myVec
[1] "a"  ""   "a"  "aa"

如果您真的想使用NA而不是“”,可以使用以下方式:

is.na(myVec) <- nchar(myVec) == 0L
myVec
[1] "a"  NA   "a"  "aa"

一些修改: 请注意您可以将最后两行合并成一行:
myVec <- sapply(myMatch, function(x) {if(length(x) == 1) NA_character_ else x[2]})
NA的默认数据类型是逻辑型,使用它会导致额外的数据转换。使用字符版本的NA_character_可以避免这种情况。
甚至更好的提取最后一行的方法是使用[:

sapply(myMatch, `[`, 2)
[1] "a"  NA   "a"  "aa"

因此,您可以在一行代码中完成整个操作,让它变得非常易读:

sapply(regmatches(x, m, invert=NA), `[`, 2)

1

使用与您相同或类似的结构 -

chars <- c("abc", "def", "cba a", "aa")    

chars[
   regexpr("a+", chars, perl=TRUE) > 0
][1] #abc

chars[
   regexpr("q", chars, perl=TRUE) > 0
][1]  #NA

#vector[
#    find all indices where regexpr returned positive value i.e., match was found
#][return the first element of the above subset]

编辑 - 似乎我误解了问题。但是由于两个人发现这很有用,所以我会让它留下来。


4
这个工作为什么能够成功以及是如何运作的一些解释会很好(暗示,暗示)。 - Johan
1
我认为Johan的意思是(提示)这并没有完全返回OP所需要的。 - Ricardo Saporta

0
你可以使用 stringr::str_extract(string, pattern)。如果没有匹配项,它将返回 NA。它的函数接口比 regmatches() 更简单。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接