strsplit与gregexpr不一致

13

这个评论 是关于 这个问题 的,它应该使用 strsplit 可以得到所需的结果,但实际上并没有,尽管它似乎正确地匹配了字符向量中的第一个和最后一个逗号。使用gregexprregmatches可以证明这一点。

那么为什么在这个例子中strsplit会在每个逗号处分割,尽管regmatches只返回相同正则表达式的两个匹配项?

#  We would like to split on the first comma and
#  the last comma (positions 4 and 13 in this string)
x <- "123,34,56,78,90"

#  Splits on every comma. Must be wrong.
strsplit( x , '^\\w+\\K,|,(?=\\w+$)' , perl = TRUE )[[1]]
#[1] "123" "34"  "56"  "78"  "90" 


#  Ok. Let's check the positions of matches for this regex
m <- gregexpr( '^\\w+\\K,|,(?=\\w+$)' , x , perl = TRUE )

# Matching positions are at
unlist(m)
[1]  4 13

#  And extracting them...
regmatches( x , m )
[[1]]
[1] "," ","

咦?发生了什么事情?


3
我猜测strsplit函数会在每次分割后迭代/递归地处理剩余的字符串,比如说 "123,34,56,78,90" -> ["123", "34,56,78,90"] -> ["123", "34", "56,78,90"]。我对R语言一无所知,但这个假设是可以进行测试的,直到你找到更好的解释为止 :) 或者也有可能只是实现的简单错误,你可以尝试不同版本的R。 - Aprillion
@deathApril 我认为这实际上与全局 vs. 非全局替换有关。我假设 strsplit 在第一次匹配时执行非全局分割,因为你使用 regexpr 而不是 gregexpr 得到相同的结果。我想知道是否可能使 strsplit 进行全局匹配...? - Simon O'Hanlon
1
表达式 '/^\w+\K,|,(?=\w+$)/' 在 PHP 中使用 'preg_split()' 正确地拆分了字符串。看起来这可能表明 PCRE 的 r 实现存在问题。 - ridgerunner
不确定,但我认为这可能与Josh的这个问答有关。 - Arun
1个回答

10

根据R文档中的描述,@Aprillion提出的理论是精确的:

应用于每个输入字符串的算法是

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.
}

换句话说,每次迭代^将与一个新字符串的开头匹配(不包括前面的项目)。

为了简单阐明这个行为:

> x <- "12345"
> strsplit( x , "^." , perl = TRUE )
[[1]]
[1] "" "" "" "" ""

这里,您可以看到使用前瞻断言作为分隔符的行为结果(感谢@JoshO'Brien提供的链接)。


3
完全正确。这里有一个相关的答案,讨论了关于R的strsplit()函数的类似问题:https://dev59.com/0GUp5IYBdhLWcg3wCD_4#15578980 - Josh O'Brien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接