testingR中string中的字符

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

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

如果“value”作为string“chars”的一部分出现,我想返回TRUE。 在下面的情况下,我想要返回false:

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

使用grepl函数

 grepl(value, chars) # TRUE 

回答

叹了口气,花了45分钟才find这个简单问题的答案。 答案是: 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 R egular E xpression P rint”的首字母缩写,它会读取input的行,然后打印它们,如果它们符合你给出的参数。 “全局”意味着匹配可能发生在input行的任何地方,我将在下面解释“正则expression式”,但是这个想法是匹配string的更聪明的方法(R称之为“字符”,例如class("abc") )和“打印”,因为它是一个命令行程序,发出输出意味着打印到它的输出string。

现在, grep程序基本上是一个从input行到输出行的filter。 而且似乎R的grep函数同样需要一些input。 由于我完全不知道的原因(我大约一小时前才开始玩R),它返回一个匹配索引的向量,而不是匹配列表。

但是,回到原来的问题,我们真正想要知道的是,我们是否在大海捞针中发现了一个真正的/错误的价值。 他们显然决定命名这个函数grepl ,就像在“grep”中一样,但是有一个“Logical”返回值(他们调用true和false逻辑值,例如class(TRUE) )。

所以,现在我们知道这个名字来自哪里以及它应该做什么。 让我们回到正则expression式。 即使它们是string,参数也用于构build正则expression式(以下简称为正则expression式)。 正则expression式是一种匹配string的方式(如果这个定义让你感到刺激,那就放手吧)。 例如,正则expression式a匹配字符"a" ,正则expression式a*匹配字符"a" 0或更多次,正则expression式a+匹配字符"a" 1次或更多次。 因此,在上面的例子中,我们正在search1+2的针,当作为正则expression式处理时,意味着“一个或多个1后面跟着一个2”…但是我们的后面加上了!

1 + 2作为正则表达式

所以,如果你在没有fixed情况下使用grepl ,那么你的针会不小心成为草垛,而且偶尔也会频繁地工作,我们可以看到它甚至可以用于OP的例子。 但这是一个潜在的错误! 我们需要告诉它input是一个string,而不是正则expression式,显然是fixed的。 为什么修复? 没有线索,书签这个答案B / C你可能需要再看5次,然后才能记住它。

一些最后的想法

你的代码越好,你需要了解的历史就越less。 每个参数至less有两个有趣的值(否则它不需要是参数),文档在这里列出9个参数,这意味着至less有2 ^ 9 = 512个方法来调用它,这是很多工作写,testing和记忆…分离这些function(拆分它们,去除彼此之间的依赖关系,string事情不同于正则expression式事物不同于向量事物)。 有些选项也是相互排斥的,不要给用户不正确的方法来使用代码,即有问题的调用应该是结构上无意义的(比如传递一个不存在的选项),而不是逻辑上的荒谬(你必须发出警告来解释它)。 用比喻来说:用一堵墙代替10楼一侧的前门比悬挂一个警告它的用途要好的标志要好,但要么比两者都好。 在一个接口中,函数定义了参数应该看起来像什么,而不是调用者(因为调用者依赖于函数,推断每个人可能想要调用它的所有东西,使函数也依赖于调用者,而这种types周期性的依赖会很快阻塞系统,永远不会提供你期望的好处)。 对types的模棱两可非常谨慎,这是一个devise缺陷,像TRUE0"abc"都是向量。

你想要grepl

 > chars <- "test" > value <- "es" > grepl(value, chars) [1] TRUE > chars <- "test" > value <- "et" > grepl(value, chars) [1] FALSE 

使用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 

以防万一你也想检查一个string(或一组string)是否包含多个子string,你也可以使用'|' 在两个子串之间。

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

你会得到

 [1] TRUE FALSE FALSE TRUE 

因为第一个字有子string“as”,而最后一个字包含子string“at”

你可以使用grep

 grep("es", "Test") [1] 1 grep("et", "Test") integer(0) 

使用grepgrepl 但要注意是否要使用正则expression式

默认情况下, grep和相关采取一个正则expression式来匹配,而不是一个文字的子string。 如果你不希望这样做,而且你试图匹配一个无效的正则expression式,那么这是行不通的:

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

要做一个真正的子串testing,使用fixed = TRUE

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

如果你确实想要正则expression式,那很好,但这不是OP所要求的。

另外,可以使用“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