R-字符串中元素的正则表达式匹配

时间:2019-08-20 17:38:34

标签: r regex

我想知道字符串中是否有任何元素出现在其他字符串中。

我的数据包含数百万行,其结构为以下模拟数据:

dt <- data.table(product = c("A", "B", "C", "A,C,E", "A,B", "A,B,C", "D", "A", "B", "A", "A", "A,B,C", "D", "D"),
              stock = c("A", "A,B", "A,B,C", "A,B,C,E", "A,B,C,E", "A,B,C,E", "A,B,C,D,E", "A", "A,B", "A,B", "A", "A,B,C", "A,B,C,D", "A,B,C,D"), stringsAsFactors = F)


dt[, product.2 := shift(product, type = "lead")]
dt[, product.3 := shift(product, n = 2, type = "lead")]

> dt
product     stock product.2 product.3
 1:       A         A         B         C
 2:       B       A,B         C     A,C,E
 3:       C     A,B,C     A,C,E       A,B
 4:   A,C,E   A,B,C,E       A,B     A,B,C
 5:     A,B   A,B,C,E     A,B,C         D
 6:   A,B,C   A,B,C,E         D         A
 7:       D A,B,C,D,E         A         B
 8:       A         A         B         A
 9:       B       A,B         A         A
10:       A       A,B         A     A,B,C
11:       A         A     A,B,C         D
12:   A,B,C     A,B,C         D         D
13:       D   A,B,C,D         D      <NA>
14:       D   A,B,C,D      <NA>      <NA>

根据这些数据,我想了解以下内容:

  1. 如果comma中的任何元素(用product.3分隔)在product.2中出现
  2. 如果comma中没有出现product.3中的任何元素(用stock分隔)。
  3. comma中的所有元素(由product.3分隔)是否都在stock中出现?

预期结果是这样的:

> dt
product     stock product.2 product.3 outcome1 outcome2 outcome3
 1:       A         A         B         C    FALSE    FALSE    FALSE
 2:       B       A,B         C     A,C,E     TRUE     TRUE    FALSE
 3:       C     A,B,C     A,C,E       A,B     TRUE     TRUE     TRUE
 4:   A,C,E   A,B,C,E       A,B     A,B,C     TRUE     TRUE     TRUE
 5:     A,B   A,B,C,E     A,B,C         D    FALSE    FALSE    FALSE
 6:   A,B,C   A,B,C,E         D         A    FALSE     TRUE     TRUE
 7:       D A,B,C,D,E         A         B    FALSE     TRUE     TRUE
 8:       A         A         B         A    FALSE     TRUE     TRUE
 9:       B       A,B         A         A     TRUE     TRUE     TRUE
10:       A       A,B         A     A,B,C     TRUE     TRUE    FALSE
11:       A         A     A,B,C         D    FALSE    FALSE    FALSE
12:   A,B,C     A,B,C         D         D     TRUE    FALSE    FALSE
13:       D   A,B,C,D         D      <NA>    FALSE    FALSE    FALSE
14:       D   A,B,C,D      <NA>      <NA>    FALSE    FALSE    FALSE

该问题是有关Stackoverflow的this问题的一部分。

编辑08/20/2019 :包括第三项预期结果。

2 个答案:

答案 0 :(得分:4)

library(data.table)
library(stringr)

根据?str_detect

  

通过字符串和模式进行矢量化。等效于grepl(pattern,x)。有关grep(pattern,x)的等效信息,请参见str_which()。

因此,一种选择是将,替换为|(或匹配项),然后将“ product.2”和“ product.3”的对应元素直接与“ stock”比较进行比较在“ product.3”上。然后,将NA的{​​{1}}元素替换为FALSE

set

前两行代码可以简化为@ d.b所述

dt[, outcome1 := str_detect(product.2, str_replace_all(product.3, ",", "|"))]
dt[, outcome2 := str_detect(stock, str_replace_all(product.3, ",", "|"))]
for(j in names(dt)[5:6]) set(dt, i = which(is.na(dt[[j]])), j = j, value = FALSE)
dt
#    product     stock product.2 product.3 outcome1 outcome2
# 1:       A         A         B         C    FALSE    FALSE
# 2:       B       A,B         C     A,C,E     TRUE     TRUE
# 3:       C     A,B,C     A,C,E       A,B     TRUE     TRUE
# 4:   A,C,E   A,B,C,E       A,B     A,B,C     TRUE     TRUE
# 5:     A,B   A,B,C,E     A,B,C         D    FALSE    FALSE
# 6:   A,B,C   A,B,C,E         D         A    FALSE     TRUE
# 7:       D A,B,C,D,E         A         B    FALSE     TRUE
# 8:       A         A         B         A    FALSE     TRUE
# 9:       B       A,B         A         A     TRUE     TRUE
#10:       A       A,B         A     A,B,C     TRUE     TRUE
#11:       A         A     A,B,C         D    FALSE    FALSE
#12:   A,B,C     A,B,C         D         D     TRUE    FALSE
#13:       D   A,B,C,D         D      <NA>    FALSE    FALSE
#14:       D   A,B,C,D      <NA>      <NA>    FALSE    FALSE

更新

随着OP问题的更新

dt[, paste0("outcome", 1:2) := lapply(.SD, str_detect, 
 pattern = str_replace_all(product.3, ",", "|")), .SDcols = c("product.2", "stock")]

答案 1 :(得分:3)

split product.3以逗号分隔,然后使用grepl检查它是否出现在product.2stock

temp = strsplit(dt$product.3, ",")
sapply(seq_along(temp), function(i){
    any(sapply(temp[[i]], function(x) grepl(x, dt$product.2[i])))
})
# [1] FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE
#[12]  TRUE    NA    NA
sapply(seq_along(temp), function(i){
    any(sapply(temp[[i]], function(x) grepl(x, dt$stock[i])))
})
# [1] FALSE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
#[12] FALSE    NA    NA