【问题标题】:Return original search terms for grep in R在 R 中返回 grep 的原始搜索词
【发布时间】:2013-05-09 19:00:43
【问题描述】:

我有一个项目列表和一个搜索词列表,我正在尝试做两件事:

  1. 在项目中搜索与任何搜索词匹配的项,并返回 true 如果找到匹配项。
  2. 对于所有返回 true 的项目(即存在匹配项),我想 还返回在步骤 1 中匹配的原始搜索词。

所以,给定以下数据框:

             items
1             alex
2 alex is a person
3   this is a test
4            false
5    this is cathy

以及以下搜索词列表:

"alex"      "bob"       "cathy"     "derrick"   "erica"     "ferdinand"

我想创建以下输出:

             items matches original
1             alex    TRUE     alex
2 alex is a person    TRUE     alex
3   this is a test   FALSE     <NA>
4            false   FALSE     <NA>
5    this is cathy    TRUE     cathy

第 1 步相当简单,但第 (2) 步有问题。要创建“匹配”列,我使用grepl() 创建一个变量,如果d$items 中的一行在搜索词列表中,则该变量为TRUE,否则为FALSE

对于第 2 步,我的想法是我应该能够在指定 value = T 时只使用 grep(),如下面的代码所示。但是,这会返回错误的值:它不会返回 grep 匹配的原始搜索词,而是返回匹配项的值。所以我得到以下输出:

            items matches original
1             alex    TRUE     alex
2 alex is a person    TRUE     alex is a person
3   this is a test   FALSE     <NA>
4            false   FALSE     <NA>
5    this is cathy    TRUE     this is cathy

这是我现在使用的代码。任何想法将不胜感激!

# Dummy data and search terms
d = data.frame(items = c("alex", "alex is a person", "this is a test", "false", "this is cathy"))
searchTerms = c("alex", "bob", "cathy", "derrick", "erica", "ferdinand")

# Return true iff search term is found in items column, not between letters
d$matches = grepl(paste("(^| |[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ])", 
    searchTerms, "($| |[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ])", sep = "", 
    collapse = "|"), d[,1], ignore.case = TRUE
)

# Subset data
dMatched = d[d$matches==T,]   

# This is where the problem is: return the value that was originally matched with grepl above
dMatched$original = grep(paste("(^| |[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ])", 
    searchTerms, "($| |[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ])", sep = "", 
    collapse = "|"), dMatched[,1], ignore.case = TRUE, value = TRUE
)


d$original[d$matches==T] = dMatched$original

【问题讨论】:

  • 你可以用[:alpha:]替换长字符串。
  • 您可能想查看regmatches 函数。
  • @Thomas:感谢您的提示。但是,[:alpha:] 和其他预定义的字符类似乎对我不起作用。它必须与我的语言环境有关。从关于字符类的正则表达式文档中:“(因为它们的解释取决于语言环境和实现,所以最好避免使用它们。)指定所有 ASCII 字母的唯一可移植方法是将它们全部列为字符类 [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]。 "
  • @SteveS 是的,通常对我有用,所以我不知道该警告总体上有多准确。
  • 语法为grep("[[:alpha:]]", c("123", "one"))或为否定"[^[:alpha:]]";如果文件的编码很重要,那么您可能不会对寻找 ASCII 字母感到满意,因此“便携式”注释可能与您解释它的方式无关。

标签: r regex search


【解决方案1】:

感谢 Dason 提供的有用提示!我能够使用regmatches() 解决我的问题。这是我的代码,从最初的问题开始:

# This is where the problem is: return the value that was originally matched with grepl above
m = regexpr(paste("(^| |[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ])", 
    searchTerms, "($| |[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ])", sep = "", 
    collapse = "|"), dMatched[,1], ignore.case = TRUE 
)

dMatched$original = regmatches(dMatched[,1], m)

d$original[d$matches==T] = dMatched$original

这将返回以下输出,这正是我想要的:

             items matches original
1             alex    TRUE     alex
2 alex is a person    TRUE    alex 
3   this is a test   FALSE     <NA>
4            false   FALSE     <NA>
5    this is cathy    TRUE    cathy

【讨论】:

    【解决方案2】:

    不完全是您想要的,但您可以使用qdaptermco 函数来执行此操作。如果您在同一个句子中有两个名字,这将有所帮助:

    library(qdap)
    termco(d$items, 1:nrow(d), searchTerms)
    
    ## > termco(d$items, 1:nrow(d), searchTerms)
    ##   nrow(d word.count       alex bob     cathy derrick erica ferdinand
    ## 1      1          1 1(100.00%)   0         0       0     0         0
    ## 2      2          4  1(25.00%)   0         0       0     0         0
    ## 3      3          4          0   0         0       0     0         0
    ## 4      4          1          0   0         0       0     0         0
    ## 5      5          3          0   0 1(33.33%)       0     0         0
    

    要使用 qdap 获得所需的内容,您可以使用:

    dat <- termco(d$items, 1:nrow(d), searchTerms)$raw
    terms <- character()
    
    for (i in 3:ncol(dat)){
        terms <- paste(terms, ifelse(dat[, i] == 1, colnames(dat)[i], ""))
    }
    
    d$matches <- as.logical(rowSums(dat[, -c(1:2)]))
    x <- gsub(" ", ", ", clean(trim(terms)))
    d$original <- replacer(x, "", NA)
    
    ## > d
    ##              items matches original
    ## 1             alex    TRUE     alex
    ## 2 alex is a person    TRUE     alex
    ## 3   this is a test   FALSE     <NA>
    ## 4            false   FALSE     <NA>
    ## 5    this is cathy    TRUE    cathy
    

    【讨论】:

    • 这也是一个非常好的解决方案。我想我更喜欢它,因为它还告诉您多个搜索词是否与项目列表匹配。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    相关资源
    最近更新 更多