为了账号安全,请及时绑定邮箱和手机立即绑定

为什么strsplit会使用肯定的先行和后向断言匹配?

为什么strsplit会使用肯定的先行和后向断言匹配?

慕村9548890 2019-12-04 10:02:30
常识和使用的健全性检查gregexpr()表明,下面的先行断言和先行断言应分别在中的一个位置精确匹配testString:testString <- "text XX text"BB  <- "(?<= XX )"FF  <- "(?= XX )"as.vector(gregexpr(BB, testString, perl=TRUE)[[1]])# [1] 9as.vector(gregexpr(FF, testString, perl=TRUE)[[1]][1])# [1] 5strsplit()但是,使用那些匹配位置的方式有所不同,testString在使用后向声明时,会在一个位置拆分,而在使用前瞻性声明时,会在两个位置拆分(其中第二个似乎不正确)。strsplit(testString, BB, perl=TRUE)# [[1]]# [1] "text XX " "text"    strsplit(testString, FF, perl=TRUE)# [[1]]# [1] "text"    " "       "XX text"我有两个问题:(问题1)这是怎么回事?和(Q2)怎么能得到strsplit()得到更好的表现?更新: Theodore Lytras的出色答案解释了正在发生的事情,因此可以解决(Q1)。我的答案建立在他确定解决方法(Q2)的基础上。
查看完整描述

3 回答

?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

我不确定是否将其视为错误,因为我认为这是基于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(匹配项的左侧)的字符串,并将其与匹配项一起从字符串中删除,但匹配项的长度为零。


现在剩下的字符串是funky town,并且前行在位置1处匹配。但是,没有什么要删除的,因为在匹配项的左侧没有任何内容,并且匹配项的长度为零。因此,算法陷入了无限循环。显然,R通过拆分单个字符来解决此问题,顺便说一下,这是strsplit使用空的正则表达式(当参数为ing时split="")所记录的行为。在此之后,剩下的字符串是unky town,由于没有匹配项,因此将作为最后一个拆分返回。


Lookbehinds没问题,因为每个匹配项都被拆分并从剩余的字符串中删除,因此算法永远不会卡住。


乍一看,这种行为看起来很奇怪。但是,否则,行为将违背前瞻零长度的假设。鉴于strsplit已记录了该算法,我相信这不符合错误的定义。


查看完整回答
反对 回复 2019-12-04
?
大话西游666

TA贡献1817条经验 获得超14个赞

基于Theodore Lytras对substr()行为的仔细说明,一种合理的解决方法是在待匹配的超前断言前面加上一个与任何单个字符匹配的肯定后向断言:


testString <- "take me to funky town"

FF2 <- "(?<=.)(?=funky)"

strsplit(testString, FF2, perl=TRUE)

# [[1]]

# [1] "take me to " "funky town" 


查看完整回答
反对 回复 2019-12-04
?
catspeake

TA贡献1111条经验 获得超0个赞

对我来说似乎是个虫子。具体来说,这似乎不仅仅与空格有关,而是任何孤独的超前行为(正数或负数):


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"

也许类似的东西可以作为解决方法。


查看完整回答
反对 回复 2019-12-04
  • 3 回答
  • 0 关注
  • 690 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信