R stringr中str_replace与str_pad结合异常:Bug还是人为失误?
str_replace与str_pad组合失效的原因解析
环境:R 4.1.3,stringr包1.4.0版本
问题重现
执行以下代码时出现不符合预期的结果:
stringr::str_replace(string = "5", pattern = "([0-9]+)", replacement = stringr::str_pad(string = "\\1", width = 3, side = "left", pad = "0"))
- 预期结果:
"005" - 实际结果:
"05"
单独测试验证
单独执行各部分逻辑均符合预期:
- 填充测试
stringr::str_pad(string = "5", width = 3, side = "left", pad = "0")
返回"005"
- 正则匹配测试
stringr::str_replace(string = "5", pattern = "([0-9]+)", replacement = "\\1")
返回"5"
核心失效原因
问题出在代码执行顺序和替换参数的解析逻辑:
当直接将str_pad("\\1", ...)作为replacement参数时,R会先执行str_pad函数,此时"\\1"是一个字面量字符串(转义后实际是\和1两个字符,长度为2)。str_pad会把这个长度为2的字符串补到3位,得到"0\\1"。
之后str_replace才会处理正则替换,把"0\\1"里的\\1替换成捕获到的"5",最终结果就是"05"——相当于先给字面量的\\1补0,再替换捕获组,自然少了一个前置0。
补充测试验证
补充测试的结果也能佐证这个逻辑:
# 匿名函数接收捕获组内容,返回其长度 stringr::str_replace(string = "5", pattern = "([0-9]+)", replacement = {\(x) as.character(nchar(x))}) # 返回"1"(捕获组内容"5"的长度为1) # 直接计算字面量"\\1"的长度,再作为替换值 stringr::str_replace(string = "5", pattern = "([0-9]+)", replacement = as.character(nchar("\\1"))) # 返回"2"(字面量"\\1"的长度为2,与捕获组内容无关)
可行方案的逻辑
使用匿名函数作为replacement时,str_replace会将捕获到的实际内容(这里是"5")作为参数传给函数,此时str_pad处理的是真实的捕获值,因此能得到正确的"005":
stringr::str_replace(string = "5", pattern = "([0-9]+)", replacement = {\(x) stringr::str_pad(string = x, width = 3, side = "left", pad = "0")})
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

