为什么strsplit使用正预测先行和向后断言匹配不同?(Why does strsplit use

2019-07-22 17:36发布

常识和使用完整性检查gregexpr()表示,下面的向后看和前瞻断言应该每场比赛在只有一个位置testString

testString <- "text XX text"
BB  <- "(?<= XX )"
FF  <- "(?= XX )"

as.vector(gregexpr(BB, testString, perl=TRUE)[[1]])
# [1] 9
as.vector(gregexpr(FF, testString, perl=TRUE)[[1]][1])
# [1] 5

strsplit()但是,使用这些比赛的地点不同,拆分testString一个位置使用向后断言的时候,但在两个位置-第二这似乎不正确-使用前向断言时。

strsplit(testString, BB, perl=TRUE)
# [[1]]
# [1] "text XX " "text"    

strsplit(testString, FF, perl=TRUE)
# [[1]]
# [1] "text"    " "       "XX text"

我有两个问题:(Q1)这是怎么回事吗? 和(Q2)一个人如何能得到strsplit()得到更好的表现?


更新:西奥多Lytras'优秀的答案解释这是怎么回事,所以地址(Q1)。 我的答案建立在他找出补救,寻址(Q2)。

Answer 1:

我不知道这是否有资格作为一个bug,因为我相信基于R文件上这是预期行为。 从?strsplit

施加到每个输入字符串的算法是

 repeat { if the string is empty break. if there is a match add the string to the left of the match to the output. remove the match and all to the left of it. else add the string to the output. break. } 

注意,这意味着,如果在(非空)字符串的开头匹配,则输出的第一个元素是“‘’”,但是,如果存在匹配于字符串的端,所述输出是相同移除了匹配。

的问题是,先行(和反向预搜索)断言零长度。 因此,例如,在这种情况下:

FF <- "(?=funky)"
testString <- "take me to funky town"

gregexpr(FF,testString,perl=TRUE)
# [[1]]
# [1] 12
# attr(,"match.length")
# [1] 0
# attr(,"useBytes")
# [1] TRUE

strsplit(testString,FF,perl=TRUE)
# [[1]]
# [1] "take me to " "f"           "unky town" 

所发生的是孤独先行(?=funky)在位置12匹配,从而第一分割包含字符串至位置11(左匹配的),并且它被从串与匹配,其删除,一起- however-长度为零。

现在剩下的字符串是funky town ,并先行在位置1。但是没有什么可去除相匹配,因为没有什么在比赛的左边是,和比赛本身长度为零。 因此,该算法是停留在一个无限循环。 显然ř通过分割一个单一的字符,这是顺便当记录的行为可以解决此strsplit用空正则表达式荷兰国际集团(当参数split="" )。 在此之后,剩下的字符串是unky town ,因为没有匹配它返回最后的分割。

Lookbehinds是没有问题的,因为每场比赛被分割,并从剩余的字符串删除,因此该算法是从来没有卡住。

诚然,这种行为乍看上去怪异。 然而,否则行为将违反长度为零的向前看符号的假设。 鉴于strsplit算法进行了说明,我相信这不符合一个错误的定义。



Answer 2:

基于西奥多Lytras'仔细解释substr()的行为,一个合理的清洁解决方法是用一个积极的向后断言匹配任何单个字符前缀待匹配的前向断言:

testString <- "take me to funky town"
FF2 <- "(?<=.)(?=funky)"
strsplit(testString, FF2, perl=TRUE)
# [[1]]
# [1] "take me to " "funky town" 


Answer 3:

看起来像我的错误。 这似乎不只是涉及到空间,具体而言,而是任何孤独前瞻(正或负):

FF <- "(?=funky)"
testString <- "take me to funky town"
strsplit(testString,FF,perl=TRUE)
# [[1]]
# [1] "take me to " "f"           "unky town"  

FF <- "(?=funky)"
testString <- "funky take me to funky funky town"
strsplit(testString,FF,perl=TRUE)
# [[1]]
# [1] "f"                "unky take me to " "f"                "unky "           
# [5] "f"                "unky town"       


FF <- "(?!y)"
testString <- "xxxyxxxxxxx"
strsplit(testString,FF,perl=TRUE)
# [[1]]
# [1] "xxx"       "y"       "xxxxxxx"

似乎很好地工作,如果给定的东西,随着零宽度断言,如捕捉:

FF <- " (?=XX )"
testString <- "text XX text"
strsplit(testString,FF,perl=TRUE)
# [[1]]
# [1] "text"    "XX text"

FF <- "(?= XX ) "
testString <- "text XX text"
strsplit(testString,FF,perl=TRUE)
# [[1]]
# [1] "text"    "XX text"

也许类似的东西可能会作为一种解决方法起作用。



文章来源: Why does strsplit use positive lookahead and lookbehind assertion matches differently?
标签: regex r strsplit