首页 > 解决方案 > 返回字符串模式匹配加上模式前后的文本

问题描述

假设我有 5 个人的日记条目,我想确定他们是否提到任何与食物相关的关键词。在确定它们是否与食物相关之前,我希望输出带有一个单词窗口的关键字,以提供上下文。

搜索应该不区分大小写,如果关键字嵌入另一个词中就可以了。例如,如果关键字是“大米”,我想输出包含“价格”。

假设我有以下数据:

foods <- c('corn', 'hot dog', 'ham', 'rice')
df <- data.frame(id = 1:5,
                 diary = c('I ate rice and corn today',
                            'Sue ate my corn.',
                            'He just hammed it up',
                            'Corny jokes are my fave',
                            'What is the price of milk'))

我正在寻找的输出是:

|ID|Output                          |
|--|--------------------------------|
|1 |"ate rice and", "and corn today"|
|2 |"my corn"                       |
|3 |"just hammed it"                |
|4 |"Corny jokes"                   |
|5 |"the price of"                  |

我用过strings::stri_detect,但输出包括整个日记条目。

我用过strings::stri_extract,但我找不到在关键字前后包含一个单词的方法。

标签: r

解决方案


不完全确定这是否 100% 有用但值得一试:

首先,将您的关键字定义为不区分大小写的交替模式:

patt <- paste0("(?i)(", paste0(foods, collapse = "|"), ")")

然后提取 the 上的单词left,关键字本身被称为node,以及rightusingstringr的函数上的单词str_extract_all

library(stringr)
df1 <- data.frame(
  left = unlist(str_extract_all(gsub("[.,!?]", "", df$diary), paste0("(?i)(\\S+|^)(?=\\s?", patt, ")"))),
  node = unlist(str_extract_all(gsub("[.,!?]", "", df$diary), patt)),
  right = unlist(str_extract_all(gsub("[.,!?]", "", df$diary), paste0("(?<=\\s?", patt, "\\s?)(\\S+|$)")))
  )

结果:

df1
  left node right
1  ate rice   and
2  and corn today
3   my corn      
4 just  ham   med
5      Corn     y
6    p rice    of

虽然这并不完全是预期的输出,但如果该目的是检查匹配项是否确实是关键字,它仍然可以满足您的目的。例如,在第 5 行和第 6 行中,立即提供的视图df1清楚地表明这些不是关键字匹配。

编辑

此解决方案保留以下id值:

library(tidyverse)
library(purrr)
extract_ <- function(df_row){
  df1 <- data.frame(
    id = df_row$id,    
    left = unlist(str_extract_all(gsub("[.,!?]", "", df_row$diary), paste0("(?i)(\\S+|^)(?=\\s?", patt, ")"))),
    node = unlist(str_extract_all(gsub("[.,!?]", "", df_row$diary), patt)),
    right = unlist(str_extract_all(gsub("[.,!?]", "", df_row$diary), paste0("(?<=\\s?", patt, "\\s?)(\\S+|$)")))
  )
}

df %>% 
  group_split(id) %>%    # splits data frame into list of bins, i.e. by id
  map_dfr(.x, .f = ~ extract_(.x))  # now we iterate over bins with our function
  id left node right
1  1  ate rice   and
2  1  and corn today
3  2   my corn      
4  3 just  ham   med
5  4      Corn     y
6  5    p rice    of

推荐阅读