【问题标题】:How to prevent regmatches drop non matches?如何防止正则匹配丢弃不匹配?
【发布时间】:2013-10-04 01:27:35
【问题描述】:

我想捕获第一个匹配项,如果没有匹配项返回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,但没有别的?似乎有混乱。这说明在提出问题时需要更精确,最好是要求的准确输出。

标签: regex r


【解决方案1】:

留在regexpr:

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

【讨论】:

    【解决方案2】:

    请改用regexec,因为它会返回一个列表,让您可以在unlisting 之前捕获character(0)

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

    【讨论】:

    • unlist({R[lengths(R)==0] &lt;- NA; R}) 现在也可以使用,因为在最近的 R 版本中引入了 lengths()
    【解决方案3】:

    在 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)
    

    【讨论】:

      【解决方案4】:

      使用或多或少与你相同的结构 -

      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]
      

      编辑 - 好像我误解了这个问题。但既然有两个人发现这很有用,我就让它留下来。

      【讨论】:

      • 一些解释为什么以及如何工作会很好(提示,提示)
      • 我认为 Johan 的观点(提示)是这并没有完全返回 OP 的要求
      猜你喜欢
      • 2021-11-15
      • 1970-01-01
      • 2016-07-11
      • 2019-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多