343

我试图确定一个字符串是否是另一个字符串的子集。例如:

chars <- "test"
value <- "es"

如果“value”作为字符串“chars”的一部分出现,我想返回 TRUE。在以下情况下,我想返回 false:

chars <- "test"
value <- "et"
4

9 回答 9

479

使用 grepl功能

grepl( needle, haystack, fixed = TRUE)

像这样:

grepl(value, chars, fixed = TRUE)
# TRUE

使用?grepl以了解更多信息。

于 2012-04-12T17:28:43.197 回答
201

回答

唉,我花了 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 可执行文件命名,该可执行文件本身是“ G lobal Regular E xpression P rint”的首字母缩写词,它会读取输入行,然后在它们与您提供的参数匹配时打印它们。“全局”意味着匹配可以发生在输入行的任何位置,我将在下面解释“正则表达式”,但想法是它是匹配字符串的更聪明的方式(R 称之为“字符”,例如class("abc"))和“打印" 因为它是一个命令行程序,发出输出意味着它打印到它的输出字符串。

现在,该grep程序基本上是一个过滤器,从输入行到输出行。并且似乎 R 的grep函数同样会采用一组输入。由于我完全不知道的原因(我大约一个小时前才开始使用 R),它返回匹配索引的向量,而不是匹配列表。

但是,回到你最初的问题,我们真正想要的是知道我们是否在大海捞针中找到了针,一个真/假值。他们显然决定将这个函数命名grepl为“grep”,但带有一个“逻辑”返回值(他们称之为真假逻辑值,例如class(TRUE))。

所以,现在我们知道这个名字来自哪里以及它应该做什么。让我们回到正则表达式。参数,即使它们是字符串,它们也用于构建正则表达式(以下简称:正则表达式)。正则表达式是一种匹配字符串的方法(如果这个定义激怒了你,那就放手吧)。例如,正则表达式a匹配字符"a",正则表达式a*匹配字符"a"0 次或多次,正则表达式a+匹配字符"a"1 次或多次。因此,在上面的示例中,我们正在搜索的 needle 被1+2视为正则表达式时,表示“一个或多个 1 后面跟着一个 2”……但我们的后面跟着一个加号!

1+2 作为正则表达式

所以,如果你使用了greplwithout setting fixed,你的针会不小心变成干草堆,而且会经常意外地工作,我们可以看到它甚至适用于 OP 的示例。但这是一个潜在的错误!我们需要告诉它输入是一个字符串,而不是一个正则表达式,这显然fixed是用于的。为什么固定?没有线索,将此答案加入书签 b/c 您可能需要再查找 5 次才能记住它。

最后的一些想法

你的代码越好,你需要知道的历史就越少才能理解它。每个参数至少可以有两个有趣的值(否则它不需要是一个参数),文档在这里列出了 9 个参数,这意味着至少有 2^9=512 种调用它的方法,这需要做很多工作编写,测试和记住...解耦这些函数(将它们拆分,消除彼此的依赖关系,字符串事物与正则表达式事物不同,与向量事物不同)。一些选项也是互斥的,不要给用户错误的代码使用方式,即有问题的调用应该是结构上无意义的(例如传递一个不存在的选项),而不是逻辑上无意义的(你必须发出警告来解释它)。打个比方:用墙代替 10 楼一侧的前门,总比挂一个警告不要使用它的标志要好,但两者都比两者都好。在接口中,函数定义了参数应该是什么样子,而不是调用者(因为调用者依赖于函数,推断每个人可能想要调用它的所有内容都使得函数也依赖于调用者,并且这种类型周期性依赖会迅速阻塞系统,并且永远不会提供您期望的好处)。非常警惕模棱两可的类型,这是一个设计缺陷 推断每个人都可能想要调用它的所有内容,使得函数也依赖于调用者,并且这种类型的循环依赖会迅速阻塞系统,并且永远不会提供您期望的好处)。非常警惕模棱两可的类型,这是一个设计缺陷 推断每个人都可能想要调用它的所有内容,使得函数也依赖于调用者,并且这种类型的循环依赖会迅速阻塞系统,并且永远不会提供您期望的好处)。非常警惕模棱两可的类型,这是一个设计缺陷TRUE0都是"abc"向量。

于 2016-10-15T17:48:53.673 回答
39

你想要grepl

> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
于 2012-04-12T17:28:40.123 回答
32

使用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
于 2014-03-14T09:46:12.033 回答
32

此外,可以使用“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
于 2017-06-14T02:38:39.913 回答
23

万一您还想检查一个字符串(或一组字符串)是否包含多个子字符串,您也可以使用“|” 两个子串之间。

>substring="as|at"
>string_vector=c("ass","ear","eye","heat") 
>grepl(substring,string_vector)

你会得到

[1]  TRUE FALSE FALSE  TRUE

因为第一个词有子串“as”,最后一个词含有子串“at”

于 2015-01-25T09:04:18.830 回答
10

使用greporgrepl 但要注意是否要使用正则表达式

默认情况下,grep相关采用正则表达式进行匹配,而不是文字子字符串。如果您没有预料到,并且您尝试匹配无效的正则表达式,则它不起作用:

> grep("[", "abc[")
Error in grep("[", "abc[") : 
  invalid regular expression '[', reason 'Missing ']''

要进行真正的子字符串测试,请使用fixed = TRUE.

> grep("[", "abc[", fixed = TRUE)
[1] 1

如果您确实想要正则表达式,那很好,但这不是 OP 似乎要问的。

于 2016-04-13T21:59:25.867 回答
7

您可以使用grep

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)
于 2012-04-12T17:29:03.240 回答
1

这里有类似的问题:给定一个字符串和一个关键字列表,检测哪些关键字(如果有)包含在字符串中。

此线程的建议建议stringr'sstr_detectgrepl. 以下是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

如您所见,超过 5,000 次关键字搜索迭代使用str_detectgrepl超过一个实用的字符串和关键字向量,grepl其性能比str_detect.

结果是一个布尔向量r,它标识字符串中包含哪些关键字(如果有的话)。

因此,我建议使用grepl来确定字符串中是否有任何关键字。

于 2020-06-07T16:34:43.677 回答