【问题标题】:How can I use grep with parameters in R?如何在 R 中使用带有参数的 grep?
【发布时间】:2011-05-22 19:46:15
【问题描述】:

显然我不明白 grep 在 R 中的工作方式。如果我在我的 OS X 终端上使用 grep,我可以使用参数 -o 使 grep 只返回匹配的部分。在 R 中,我找不到如何做相应的事情。阅读手册,我认为 values 是正确的方法,因为它返回字符而不是索引,但仍然返回整个字符串,因此更好。

# some string  fasdjlk465öfsdj123 
# R
test <-  fasdjlk465öfsdj123 
grep("[0-9]",test,value=TRUE) # returns  "fasdjlk465öfsdj123"

# shell
grep -o '[0-9]' fasdjlk465öfsdj123
# returns 4 6 5 1 2 3

我在 R 中缺少什么参数?

编辑:Joris Meys 的建议非常接近我想要做的。我得到一个向量作为 readLines 的结果。我想检查向量的每个元素是否有数字并返回这些数字。我真的很惊讶没有标准的解决方案。我想使用一些适用于字符串的正则表达式函数并返回匹配项,如 grep -o ,然后在该向量上使用 lapply 。 grep.custom 是最接近的——我会努力让它为我工作。

【问题讨论】:

  • 嗯,调用一些 shell grep 不是更容易吗?我该怎么做?
  • @ran2 : 更正了我的名字 :-)
  • 哎呀,对不起先生!下次你帮助我时,我会仔细检查我是否至少写对了你的名字;)
  • @ran2 :更新了我对向量的回答。或者,如果你想使用 shell grep,你可以查看?sys。在这里运行windows,所以没有机会尝试,但我相信你会自己弄明白。
  • ... 应该是 ?system 以防其他人感兴趣

标签: r regex


【解决方案1】:

Spacedman 已经说过了。如果您真的想在 shell 中模拟 grep,则必须使用 strsplit() 处理字符本身:

> chartest <- unlist(strsplit(test,""))
> chartest
 [1] "f" "a" "s" "d" "j" "l" "k" "4" "6" "5" "ö" "f" "s" "d" "j" "1" "2" "3"
> grep("[0-9]",chartest,value=T)
[1] "4" "6" "5" "1" "2" "3"

编辑:

正如 Nico 所说,如果要对完整的正则表达式执行此操作,则需要使用 gregexpr()substr()。我会做一个像这样的自定义函数:

grep.custom <- function(x,pattern){
    strt <- gregexpr(pattern,x)[[1]]
    lngth <- attributes(strt)$match.length
    stp <- strt + lngth - 1
    apply(cbind(strt,stp),1,function(i){substr(x,i[1],i[2])})
}

然后:

> grep.custom(test,"sd")
[1] "sd" "sd"
> grep.custom(test,"[0-9]")
[1] "4" "6" "5" "1" "2" "3"
> grep.custom(test,"[a-z]s[a-z]")
[1] "asd" "fsd"

EDIT2:

对于向量,使用函数Vectorize(),例如:

> X <- c("sq25dfgj","sqd265jfm","qs55d26fjm" )
> v.grep.custom <- Vectorize(grep.custom)
> v.grep.custom(X,"[0-9]+")
$sq25dfgj
[1] "25"

$sqd265jfm
[1] "265"

$qs55d26fjm
[1] "55" "26"

如果您想从 shell 调用 grep,请参阅 ?system

【讨论】:

  • 如果你想匹配多个字符,那是行不通的。您真的应该使用gregexpr,请参阅我的答案作为示例。
  • 很接近,刚刚编辑了我的帖子。谢谢你的帮助,我会努力让它为我工作......
  • 我不能两次投票,但至少我可以接受这个答案。不知道矢量化。还有很多东西要学...
【解决方案2】:

这是因为 R 的 'grep' 适用于向量 - 它会搜索每个元素并返回匹配的元素索引。它说“这个向量中的哪些元素与这个模式匹配?”例如,这里我们制作一个 3 的向量,然后问“这个向量中的哪些元素中只有一个数字?”

> test = c("fasdjlk465öfsdj123","nonumbers","123")
> grep("[0-9]",test)
[1] 1 3

元素 1 和 3 - 不是 2,它只是字符。

您可能想要 gsub - 用任何内容替换不匹配数字的任何内容:

> gsub("[^0-9]","",test)
[1] "465123" ""       "123" 

【讨论】:

  • gsub 为 +1。就我而言,两个连续的 gsub 确实完成了这项工作。显然没有单一的好解决方案,但有几种方法可以做到......
  • @ran2 : 呵呵,你可能早就发现了,对于你在编辑中订阅的问题,这可能是最干净的解决方案。问题是,作为我最初给出的解决方案,它只适用于非常简单的情况。对于更复杂的正则表达式,您需要更多。另请参阅@nico 的答案,他是对的。
  • @Joris Meys:找到适合现在的东西是一回事,但从不同的解决方案中学习是另一回事。
【解决方案3】:

所有这些与字符串一起跳舞的问题是 stringr 包旨在解决的问题。

library(stringr)
str_extract_all('fasdjlk465fsdj123', '[0-9]')

[[1]]
[1] "4" "6" "5" "1" "2" "3"

# It is vectorized too
str_extract_all(rep('fasdjlk465fsdj123',3), '[0-9]')

[[1]]
[1] "4" "6" "5" "1" "2" "3"

[[2]]
[1] "4" "6" "5" "1" "2" "3"

[[3]]
[1] "4" "6" "5" "1" "2" "3"

stringr 背后的动机是在两个原则下统一 R 中的字符串操作:

  • 对函数使用合理且一致的命名方案 (str_do_something)。

  • 让所有在其他编程语言中走一步的字符串操作,而在 R 中走五十步,在 R 中只走一步。

【讨论】:

    【解决方案4】:

    grep 只会告诉你字符串是否匹配。

    例如,如果您有:

    values <- c("abcde", "12345", "abc123", "123abc")
    

    然后

    grep <- ("[0-9]", values)
    [1] 2 3 4
    

    这告诉您数组的元素 2,3 和 4 与正则表达式匹配。您可以通过 value=TRUE 返回字符串而不是索引。

    如果您想查看比赛在哪里进行,您可以改用regexpr

    > regexpr("[0-9]", values)
    [1] -1  1  4  1
    attr(,"match.length")
    [1] -1  1  1  1
    

    告诉你第一场比赛发生在哪里。

    更好的是,您可以使用gregexpr 进行多个匹配

    > gregexpr("[0-9]", values)
    [[1]]
    [1] -1
    attr(,"match.length")
    [1] -1
    
    [[2]]
    [1] 1 2 3 4 5
    attr(,"match.length")
    [1] 1 1 1 1 1
    
    [[3]]
    [1] 4 5 6
    attr(,"match.length")
    [1] 1 1 1
    
    [[4]]
    [1] 1 2 3
    attr(,"match.length")
    [1] 1 1 1
    

    【讨论】:

      【解决方案5】:

      不知道你从哪里得到的印象

      > test <- "fasdjlk465öfsdj123"
      > grep("[0-9]",test)
      [1] 1
      

      返回"fasdjlk465öfsdj123"

      如果要返回匹配项,则需要将 test 分解为其组成部分,grep 在这些部分上,然后使用从 grep 返回的内容来索引 test

      > test <- strsplit("fasdjlk465öfsdj123", "")[[1]]
      > matched <- grep("[0-9]", test)
      > test[matched]
      [1] "4" "6" "5" "1" "2" "3"
      

      或者直接返回匹配的字符串,看你想要什么:

      > grep("[0-9]", test, value = TRUE)
      [1] "4" "6" "5" "1" "2" "3"
      

      【讨论】:

      • 抱歉,编辑了我的帖子,忘记了 value=TRUE。这就是我产生这个想法的原因。
      • 显然我们同时有同样的想法。 +1
      • @Joris:看起来是这样,但你赢了使用unlist()! +1
      【解决方案6】:

      gsubfn 包中的strapply 可以进行这样的提取:

      > library(gsubfn)
      > strapply(c("ab34de123", "55x65"), "\\d+", as.numeric, simplify = TRUE)
           [,1] [,2]
      [1,]   34   55
      [2,]  123   65
      

      它基于apply 范式,其中第一个参数是对象,第二个是修饰符(apply 的边距,strapply 的正则表达式),第三个参数是应用于匹配项的函数.

      stringr 包中的str_extract_all(obj, re)strapply 类似,专门为函数使用c,即类似于strapply(obj, re, c)

      strapply支持R支持的正则表达式集,也支持tcl正则表达式。

      查看 gsubfn 主页http://gsubfn.googlecode.com

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-06
        • 1970-01-01
        • 2014-08-28
        • 2016-10-05
        • 1970-01-01
        • 1970-01-01
        • 2022-09-23
        • 2016-10-23
        相关资源
        最近更新 更多