【问题标题】:How to get a match when only one letter difference is allowed?当只允许一个字母差异时如何获得匹配?
【发布时间】:2015-08-29 06:03:02
【问题描述】:

我想查看我的数据集中的单词是否出现在某个文本中。使用 grepl 时,您只能得到完全匹配。使用agrepl 可以进行部分匹配。但是,我没有得到想要的结果。

示例数据:

dt <- structure(list(id = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L),
                     words = c("weg", "verte", "spiegelend", "spiegeld", "einde", "spiegel", "spiegelende", "weg", "spiegelend", "asfalt", "fata", "morgana")),
                .Names = c("id", "words"), row.names = c(NA, -12L), class = c("data.table", "data.frame"))

与:

dt <- dt[, .(id, words,
             match1=mapply(grepl, words, 
                           "hoe komt het dat de weg in de verte soms spiegelend lijkt"),
             match2=mapply(agrepl, words,
                           "hoe komt het dat de weg in de verte soms spiegelend lijkt",
                           MoreArgs=list(max.distance=1L)))]

我明白了:

> dt
    id       words match1 match2
 1:  0         weg   TRUE   TRUE
 2:  0       verte   TRUE   TRUE
 3:  0  spiegelend   TRUE   TRUE
 4:  0    spiegeld  FALSE   TRUE
 5:  0       einde  FALSE  FALSE
 6:  0     spiegel   TRUE   TRUE
 7:  0 spiegelende  FALSE   TRUE
 8:  1         weg   TRUE   TRUE
 9:  1  spiegelend   TRUE   TRUE
10:  1      asfalt  FALSE  FALSE
11:  1        fata  FALSE  FALSE
12:  1     morgana  FALSE  FALSE

如您所见,greplagrepl 的结果在第 4 行和第 7 行上有所不同。但是,我只希望在最多有一个字母差异时进行匹配。因此,第 4 行中 match2 的匹配项应该是 FALSE。更改 max.distancecosts 之类的参数也不会产生预期的结果。此外,第 6 行的两个匹配项也应该是 FALSE

例如:对于文本中的单词“spiegelend”,单词“spieglende”应该给出匹配(只有一个字母不同),但是单词“ spiegel”(两个字母不同)和单词“spiegel”(三个字母不同)应该匹配。

条件允许(但不能同时):

  • 多一个字母(例如:“spieglende”应该匹配),或者
  • 少一个字母(例如:“spiegelen”应该匹配),或者
  • 一个拼写错误(例如:“spiehelend”应该匹配)

关于如何解决这个问题的任何想法?

【问题讨论】:

  • @Jonny5 实际上,agrepl 正在使用 Levenshtein 距离。但是,使用?agrepl中指定的参数却无法得到想要的结果。
  • @nongkrong 当我想将向量中的单词与特定文本(如示例中指定)进行匹配时,我该怎么做?
  • @nongkrong 只考虑额外的字母,当来自words 的单词短一个字母时,我找不到匹配项(另请参阅问题中的指定条件)

标签: regex r string data.table


【解决方案1】:

两种解决方法,匹配 nongkrong 和 RHertel 的方法:

dt <- cbind(dt[,c("id", "words")],
         match1=mapply(grepl, dt$words, 
                       "hoe komt het dat de weg in de verte soms spiegelend lijkt"),
         match2=mapply(agrepl, dt$words,
                       "hoe komt het dat de weg in de verte soms spiegelend lijkt",
                       MoreArgs=list(max.distance=1L)),
       match3=mapply(agrepl, paste0("\\b",dt$words,"\\b"),
                       "hoe komt het dat de weg in de verte soms spiegelend lijkt",
                       MoreArgs=list(max.distance=1L, fixed=F)),
       match4=apply(adist( dt$words,  unlist(strsplit("hoe komt het dat de weg in de verte soms spiegelend lijkt", split=" "))),
                 1, function (x) any(x<=1))
                     )

match3 使用单词边界 \\b,而 match4 使用

【讨论】:

    【解决方案2】:

    我考虑过在这种情况下使用adist(),条件为&lt; 2。但我不确定它是否会产生预期的输出。这有帮助吗?

    idx <- which(adist(dt$words,dt2$words) < 2, arr.ind = T)
    dt$match <- (dt$words %in% dt2$words[idx[,2]])
    #> dt
    #   id       words match
    #1   0         weg  TRUE
    #2   0       verte  TRUE
    #3   0  spiegelend  TRUE
    #4   0    spiegeld FALSE
    #5   0       einde FALSE
    #6   0     spiegel FALSE
    #7   0 spiegelende FALSE
    #8   1         weg  TRUE
    #9   1  spiegelend  TRUE
    #10  1      asfalt FALSE
    #11  1        fata FALSE
    #12  1     morgana FALSE
    

    数据

    dt <- structure(list(id = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L),
                     words = c("weg", "verte", "spiegelend", "spiegeld", "einde", "spiegel", "spiegelende", "weg", "spiegelend", "asfalt", "fata", "morgana")),
                .Names = c("id", "words"), row.names = c(NA, -12L), class = c("data.table", "data.frame"))
    dt2 <- structure(list(id = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L),
                       words = c("hoe", "komt", "het", "dat", "de", "weg", "in", "de", "verte", "soms", "spiegelend", "lijkt")),
                  .Names = c("id", "words"), row.names = c(NA, -12L), class = c("data.table", "data.frame"))
    

    【讨论】:

      猜你喜欢
      • 2016-03-28
      • 2016-10-28
      • 2015-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 2014-04-11
      相关资源
      最近更新 更多