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”…但是我们的后面加上了!
所以,如果你在没有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缺陷,像TRUE
和0
和"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)
使用grep
或grepl
但要注意是否要使用正则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