gregexpr与str_extract_all带量词交替匹配的空匹配数量差异疑问
为什么gregexpr和str_extract_all处理
(h|a)*时的空匹配数量不同? 这个差异本质上是两个函数依赖的正则引擎不同,再加上它们对空匹配的位置处理逻辑有区别导致的,咱们一步步拆解:
先明确正则模式的含义
(h|a)*表示匹配0次或多次的h或a——这意味着空匹配(匹配0次)是完全合法的,所以我们会看到很多空字符串结果。
1. gregexpr(base R,默认PCRE引擎)的匹配逻辑
base R的gregexpr用的是PCRE正则引擎,它的匹配规则是从字符串的第一个字符位置(索引1)开始,每次匹配后强制移动到下一个字符位置(哪怕是空匹配,也不会在同一个位置重复匹配,避免无限循环)。
对字符串"xxhx"的匹配过程:
- 位置1(第一个
x):匹配0次h/a,得到空匹配,记录位置1,长度0; - 位置2(第二个
x):同样匹配0次,得到空匹配,记录位置2,长度0; - 位置3(
h):匹配到1次h,记录位置3,长度1; - 位置4(最后一个
x):匹配0次,得到空匹配,记录位置4,长度0; - 移动到位置5(字符串结束),停止匹配。
所以gregexpr返回4个匹配结果:3个空匹配(位置1、2、4)+1个"h"(位置3),对应你看到的输出:
gregexpr(pattern = "(h|a)*", "xxhx") [[1]] # [1] 1 2 3 4 # attr(,"match.length") # [1] 0 0 1 0 # attr(,"useBytes") # [1] TRUE
2. str_extract_all(stringr包,ICU引擎)的匹配逻辑
stringr系列函数依赖的是ICU正则引擎,它的匹配策略会遍历字符串所有可能的间隙位置——包括字符串开头(第一个字符之前)和结尾(最后一个字符之后)的间隙,而不只是字符所在的位置。
对字符串"xxhx"的匹配过程:
- 开头间隙(第一个
x之前):匹配0次h/a,得到空匹配""; - 第一个
x之后的间隙:匹配0次,得到空匹配""; - 第二个
x之后的间隙:匹配到h,得到"h"; h之后的间隙:匹配0次,得到空匹配"";- 最后一个
x之后的间隙:匹配0次,得到空匹配"";
所以str_extract_all返回5个匹配结果:4个空匹配+1个"h",对应你的输出:
str_extract_all(pattern = "(h|a)*", "xxhx") [[1]] # [1] "" "" "h" "" ""
总结
核心差异在于:
- PCRE引擎(gregexpr)从字符位置开始匹配,且每次匹配后强制移动一个字符位置,不包含开头前的空匹配;
- ICU引擎(str_extract_all)会覆盖所有间隙位置(开头、字符间、结尾),因此多了一个开头的空匹配,最终空匹配数量比gregexpr多1个。
内容的提问来源于stack exchange,提问作者S.Perera
相关产品推荐
相关产品推荐

