【问题标题】:R grep: is there an AND operator?R grep:有 AND 运算符吗?
【发布时间】:2012-11-02 00:10:37
【问题描述】:

假设我有以下数据框:

User.Id    Tags
34234      imageUploaded,people.jpg,more,comma,separated,stuff
34234      imageUploaded
12345      people.jpg

如何使用 grep(或其他工具)仅抓取同时包含“imageUploaded”和“people”的行?换句话说,我如何创建一个子集,其中只包含带有字符串“imageUploaded”和“people.jpg”的行,而不管顺序如何。

我试过了:

data.people<-data[grep("imageUploaded|people.jpg",results$Tags),]
data.people<-data[grep("imageUploaded?=people.jpg",results$Tags),]

有 AND 运算符吗?或者也许是另一种获得预期结果的方法?

【问题讨论】:

    标签: r regex


    【解决方案1】:

    感谢this answer,这个正则表达式似乎有效。您想使用grepl(),它返回一个逻辑索引到您的数据对象。我不会声称完全理解正则表达式的内部工作原理,但无论如何:

    x <- c("imageUploaded,people.jpg,more,comma,separated,stuff", "imageUploaded", "people.jpg")
    
    grepl("(?=.*imageUploaded)(?=.*people\\.jpg)", x, perl = TRUE)
    #-----
    [1]  TRUE FALSE FALSE
    

    【讨论】:

    • 我曾与grep("(?=imageUploaded)(?=people\\.jpg)" 玩耍,但没有成功,所以秘密似乎是a)perl=TRUE,b)分组括号和c)领先的.* 之后?=
    • people\\.jpg 不起作用所以我只是做了data.people&lt;-data[grepl("(?=.*imageUploaded)(?=.*people)",data$Tags,perl=TRUE),] 我不需要匹配 .jpg 扩展名,但我很想知道如何使用 grep 来做到这一点。
    • 有没有一种不需要 perl=TRUE 的 AND 模式?这样它就可以用于 list.files 等?
    【解决方案2】:

    我喜欢@Chase 的回答,这对我来说很有意义,但使用人们不完全理解的结构可能有点危险。

    这个答案旨在让任何想要使用@thelatemail 更直接的方法的人放心,它同样有效,并且在速度方面完全具有竞争力。这当然是我在这种情况下会使用的。 (同样令人放心的是,更复杂的 Perl 兼容正则表达式因其强大的功能和易于扩展而无需支付性能成本。)

    library(rbenchmark)
    x <- paste0(sample(letters, 1e6, replace=T), ## A longer vector of
                sample(letters, 1e6, replace=T)) ## possible matches
    
    ## Both methods give identical results
    tlm <- grepl("a", x, fixed=TRUE) & grepl("b", x, fixed=TRUE)
    pat <- "(?=.*a)(?=.*b)"
    Chase <- grepl(pat, x, perl=TRUE)
    identical(tlm, Chase)
    # [1] TRUE    
    
    ## Both methods are similarly fast
    benchmark(
        tlm = grepl("a", x, fixed=TRUE) & grepl("b", x, fixed=TRUE),
        Chase = grepl(pat, x, perl=TRUE))
    #          test replications elapsed relative user.self sys.self
    # 2       Chase          100    9.89    1.105      9.80     0.10
    # 1 thelatemail          100    8.95    1.000      8.47     0.48
    

    【讨论】:

    • 我认为,这是一个很好的答案。 tlm 方法(虽然速度很快)很容易遵循。
    【解决方案3】:

    为了便于阅读,您可以这样做:

    x <- c(
           "imageUploaded,people.jpg,more,comma,separated,stuff",
           "imageUploaded",
           "people.jpg"
           )
    
    xmatches <- intersect(
                          grep("imageUploaded",x,fixed=TRUE),
                          grep("people.jpg",x,fixed=TRUE)
                         )
    x[xmatches]
    [1] "imageUploaded,people.jpg,more,comma,separated,stuff"
    

    【讨论】:

    • 当然,简单的答案就是应用 grep 两次(一次是使用 'imageUploaded' 提取行,然后在该结果上使用 'people.jpg' 提取行)。您的解决方案不会创建临时对象(可能很大)。
    【解决方案4】:

    下面是使用 hadley 的 stringr::str_detect() 替代 grep 的方法。这避免了使用perl=true@jan-stanstrup。此外,dplyr::filter() 将返回数据帧本身内的行,因此您永远不需要离开 df。

    library(stringr)
    libary(dplyr)
     x <- data.frame(User.Id =c(34234,34234,12345), 
                     Tags=c("imageUploaded,people.jpg,more,comma,separated,stuff",
                            "imageUploaded",
                            "people.jpg"))
    
     data.people <- x %>% filter(str_detect(Tags,"(?=.*imageUploaded)(?=.*people\\.jpg)"))
     data.people
    
    # returns
    #  User.Id                                                Tags
    # 1   34234 imageUploaded,people.jpg,more,comma,separated,stuff
    

    如果“people.jpg”总是跟随“imageUploaded”,这更简单并且有效

    str_extract(x,"imageUploaded.*people\\.jpg")
    

    【讨论】:

    • 是否可以传递一个向量来匹配?您将如何使用 AND 运算符匹配以下向量中的两个元素,c("imageUploaded", "people")。
    猜你喜欢
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2013-01-22
    • 2014-04-22
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多