4.5 字符串匹配

agrepagrepl 函数做近似(模糊)匹配 (Approximate Matching or Fuzzy Matching) ,对于匹配,考虑到参数 pattern 在参数 x 中匹配时,允许参数值x存在最小可能的插入、删除和替换,这种修改叫做Levenshtein 编辑距离,max.distance 控制其细节

agrep(pattern, x, max.distance = 0.1, costs = NULL,
      ignore.case = FALSE, value = FALSE, fixed = TRUE,
      useBytes = FALSE)

agrepl(pattern, x, max.distance = 0.1, costs = NULL,
       ignore.case = FALSE, fixed = TRUE, useBytes = FALSE)

agrep 函数返回 pattern 在 x 中匹配到的一个位置向量,agrepl 返回一个逻辑向量,这一点类似 grepgrepl 这对函数,下面举例子说明

agrep("lasy", "1 lazy 2")
## [1] 1
# sub = 0 表示匹配时不考虑替换
agrep("lasy", c(" 1 lazy 2", "1 lasy 2"), max = list(sub = 0))
## [1] 2
# 默认设置下,匹配时区分大小写
agrep("laysy", c("1 lazy", "1", "1 LAZY"), max = 2)
## [1] 1
# 返回匹配到值,而不是位置下标,类似 grep(..., value = TRUE) 的返回值
agrep("laysy", c("1 lazy", "1", "1 LAZY"), max = 2, value = TRUE)
## [1] "1 lazy"
# 不区分大小写
agrep("laysy", c("1 lazy", "1", "1 LAZY"), max = 2, ignore.case = TRUE)
## [1] 1 3
startsWith(x, prefix)
  endsWith(x, suffix)

startsWithendsWith 函数用来匹配字符串的前缀和后缀,返回值是一个逻辑向量,参数 prefix 和 suffix 不要包含特殊的正则表达式字符,如点号.,举例子

# 字符串向量
search()
## [1] ".GlobalEnv"        "package:stats"     "package:graphics" 
## [4] "package:grDevices" "package:utils"     "package:datasets" 
## [7] "package:methods"   "Autoloads"         "package:base"
# 匹配以 package: 开头的字符串
startsWith(search(), "package:")
## [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE
# 或者
grepl("^package:", search())
## [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE

当前目录下,列出扩展名为 .Rmd 的文件

# list.files(path = ".", pattern = "\\.Rmd$")
# 而不是 endsWith(list.files(), "\\.Rmd")
endsWith(list.files(), ".Rmd")
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE
## [13] FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
## [25] FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE  TRUE
## [37]  TRUE FALSE FALSE  TRUE  TRUE FALSE  TRUE FALSE FALSE  TRUE  TRUE  TRUE
## [49]  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE  TRUE
## [61] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE
## [73]  TRUE  TRUE
# 或者
grepl("\\.Rmd$", list.files())
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE
## [13] FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
## [25] FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE  TRUE
## [37]  TRUE FALSE FALSE  TRUE  TRUE FALSE  TRUE FALSE FALSE  TRUE  TRUE  TRUE
## [49]  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE  TRUE
## [61] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE
## [73]  TRUE  TRUE

部分匹配(Partial String Matching)

match(x, table, nomatch = NA_integer_, incomparables = NULL)
x %in% table
charmatch(x, table, nomatch = NA_integer_)
pmatch(x, table, nomatch = NA_integer_, duplicates.ok = FALSE)

这几个 match 函数的返回值都是一个向量,每个元素是参数x在参数table中第一次匹配到的位置,charmatchpmatch(x, table, nomatch = NA_integer_, duplicates.ok = TRUE) 类似,所以 pmatch 在默认 duplicates.ok = FALSE 的情况下,若x在第二个参数table中有多次匹配就会返回 NA,因此,实际上 pmatch 只允许在第二个参数中匹配一次

match("xx", c("abc", "xx", "xxx", "xx"))
## [1] 2
1:10 %in% c(1,3,5,9)
##  [1]  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE
# charmatch 就比较奇怪,规则太多
charmatch("", "")                             # returns 1
## [1] 1
# 多个精确匹配到,或者多个部分匹配到,则返回 0
charmatch("m",   c("mean", "median", "mode", "quantile")) # returns 0
## [1] 0
# med 只在table参数值的第二个位置部分匹配到,所以返回2
charmatch("med", c("mean", "median", "mode", "quantile")) # returns 2
## [1] 2
charmatch("xx", "xx")
## [1] 1
charmatch("xx", "xxa")
## [1] 1
charmatch("xx", "axx")
## [1] NA
# 注意比较与 charmatch 的不同
pmatch("", "")                             # returns NA
## [1] NA
pmatch("m",   c("mean", "median", "mode")) # returns NA
## [1] NA
pmatch("med", c("mean", "median", "mode")) # returns 2
## [1] 2