我想确定一个字符串是否是另一个字符串的子集。例如:
chars <- "test"
value <- "es"
如果字符串“chars
”中包含“value
”,我想返回TRUE
。在以下情况下,我希望返回false:
chars <- "test"
value <- "et"
使用 grepl
函数。
grepl( needle, haystack, fixed = TRUE)
就像这样:
grepl(value, chars, fixed = TRUE)
# TRUE
使用?grepl
来了解更多信息。
vec <- replicate(100000, paste( sample(letters, 10, replace=TRUE), collapse='') )
。 - Greg Snowsystem.time(a <- grepl("abc", vec))
和 system.time(a <- grepl("abc", vec, fixed=TRUE))
,即使使用 fixed=TRUE
,速度仍然稍微慢一些。在这些短字符串中,差别不明显,但 fixed=TRUE
似乎仍然没有更快。感谢指出,在长字符串上才会真正影响 fixed=TRUE
的速度。 - Josh O'Brien唉,我花了45分钟才找到这个简单问题的答案。答案是:grepl(needle, haystack, fixed=TRUE)
# Correct
> grepl("1+2", "1+2", fixed=TRUE)
[1] TRUE
> grepl("1+2", "123+456", fixed=TRUE)
[1] FALSE
# Incorrect
> grepl("1+2", "1+2")
[1] FALSE
> grepl("1+2", "123+456")
[1] TRUE
grep
是以 Linux 可执行文件命名的,它本身是 "Global Regular Expression Print" 这个缩写,它将读取输入行,如果符合给定的参数,则会打印它们。"Global" 表示可以在输入行的任何位置进行匹配,下面我将解释 "正则表达式",但基本思想是它是一种更智能的匹配字符串的方法(R 称之为 "字符",例如 class("abc")
),而 "Print" 是因为它是一个命令行程序,发出输出意味着它打印到其输出字符串中。
现在,grep
程序基本上是一个过滤器,从输入行到输出行。看起来 R 的 grep
函数也会像它一样接受一个输入数组。出于我完全不知道的原因(我只在大约一个小时前开始使用 R),它返回与匹配项相符的索引向量,而不是匹配项列表。
但是,回到您最初的问题,我们真正想知道的是在大海捞针中是否找到了针头,即一个 true/false 值。他们显然决定将这个函数命名为 grepl
,就像 "grep" 一样,但具有 "Logical" 返回值(他们将 true 和 false 称为逻辑值,例如 class(TRUE)
)。
因此,现在我们知道了它的命名来自何处以及它应该做什么。让我们回到正则表达式。尽管参数是字符串,但它们用于构建正则表达式(以下简称 regex)。正则表达式是一种匹配字符串的方法(如果这个定义使您感到不悦,请放手)。例如,正则表达式 a
匹配字符 "a"
,正则表达式 a*
匹配字符 "a"
0 次或多次,而正则表达式 a+
则匹配字符 "a"
1 次或多次。因此,在上面的示例中,我们正在搜索的针头是 1+2
,当作为正则表达式处理时,它的意思是 "一个或多个 1 后跟一个 2"... 但我们的要求是它后面还要加上一个加号!
因此,如果您在没有设置 fixed
的情况下使用了 grepl
,则您的针头将意外地成为大海捞针中的一部分,这通常会意外地起作用,我们可以看到它甚至对 OP 的示例也有效。但这是一个隐藏的错误!我们需要告诉它输入是字符串而不是正则表达式,这似乎就是 fixed
的作用。为什么是 fixed?我不知道,记住这个答案,因为您可能需要查阅它 5 次才能记住它。
你的代码越好,你就需要更少的历史知识以便理解它。每个参数都可以有至少两个有趣的值(否则它不需要成为参数),文档
grep
是在过滤行而不是单元格。 - krevelen?grep
页面,你会发现value=TRUE会使它表现得像你最初期望的那样。一直抱怨它不按照你的预期行事只意味着在开始抱怨之前你没有阅读文档。 - IRTFMgrepl
函数:> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
同时,也可以使用"stringr" 库来完成:
> library(stringr)
> chars <- "test"
> value <- "es"
> str_detect(chars, value)
[1] TRUE
### For multiple value case:
> value <- c("es", "l", "est", "a", "test")
> str_detect(chars, value)
[1] TRUE FALSE TRUE FALSE TRUE
stringr
的优点进行了很好的讨论。 - sfuqua使用来自stringi
包的此函数:
> stri_detect_fixed("test",c("et","es"))
[1] FALSE TRUE
一些基准测试:
library(stringi)
set.seed(123L)
value <- stri_rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings
head(value)
chars <- "es"
library(microbenchmark)
microbenchmark(
grepl(chars, value),
grepl(chars, value, fixed=TRUE),
grepl(chars, value, perl=TRUE),
stri_detect_fixed(value, chars),
stri_detect_regex(value, chars)
)
## Unit: milliseconds
## expr min lq median uq max neval
## grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530 100
## grepl(chars, value, fixed = TRUE) 5.071617 5.110779 5.281498 5.523421 45.243791 100
## grepl(chars, value, perl = TRUE) 1.835558 1.873280 1.956974 2.259203 3.506741 100
## stri_detect_fixed(value, chars) 1.191403 1.233287 1.309720 1.510677 2.821284 100
## stri_detect_regex(value, chars) 6.043537 6.154198 6.273506 6.447714 7.884380 100
如果您想检查一个字符串(或一组字符串)是否包含多个子字符串,您也可以在两个子字符串之间使用 '|'。
>substring="as|at"
>string_vector=c("ass","ear","eye","heat")
>grepl(substring,string_vector)
您将获得
[1] TRUE FALSE FALSE TRUE
由于第一个单词包含子字符串 "as",且最后一个单词包含子字符串 "at"
使用 grep
或 grepl
但要注意你是否想使用正则表达式。
默认情况下,grep
和相关函数需要使用 正则表达式 进行匹配,而不是普通的字面上的子字符串。如果您没有意识到这一点,并尝试在无效的正则表达式上进行匹配,它将无法工作:
> grep("[", "abc[")
Error in grep("[", "abc[") :
invalid regular expression '[', reason 'Missing ']''
要进行真正的子字符串测试,请使用 fixed = TRUE
。
> grep("[", "abc[", fixed = TRUE)
[1] 1
如果您确实需要正则表达式,那很好,但是这似乎不是OP所要求的。grep
。grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)
本线程的建议是使用stringr
库的str_detect
函数和grepl
函数。以下是microbenchmark
包的基准测试结果:
使用
map_keywords = c("once", "twice", "few")
t = "yes but only a few times"
mapper1 <- function (x) {
r = str_detect(x, map_keywords)
}
mapper2 <- function (x) {
r = sapply(map_keywords, function (k) grepl(k, x, fixed = T))
}
然后
microbenchmark(mapper1(t), mapper2(t), times = 5000)
Unit: microseconds
expr min lq mean median uq max neval
mapper1(t) 26.401 27.988 31.32951 28.8430 29.5225 2091.476 5000
mapper2(t) 19.289 20.767 24.94484 23.7725 24.6220 1011.837 5000
str_detect
和 grepl
进行超过 5,000 次迭代的关键字搜索后,grepl
的表现比 str_detect
好得多。r
,它标识了哪些关键字(如果有)包含在字符串中。grepl
来确定字符串中是否存在任何关键字。
fixed=TRUE
,否则你会将其视为正则表达式而不是字符串。请参考我在2016年10月发表的回答。 - Joshua Cheekfixed=TRUE
,要么就会出现悄悄而微妙地破坏数据的错误。 - Joshua Cheek