R语言:如何将...参数传递给str_replace_all且避免提前求值?
如何在不提前求值的情况下处理
...参数并传递给str_replace_all()? 我需要编写一个基于stringr::str_c()的包装函数,通过...接收任意数量的字符向量输入。要求在将这些向量传给str_c()前,先用stringr::str_replace_all()做预处理,但str_replace_all()仅接受单个字符向量作为输入。同时希望保留...的延迟求值特性,避免提前强制求值所有参数,并且处理后的结果要能直接传递给str_c()。
原有的解决方案通过unlist(list(...))合并所有输入后处理,虽然能运行,但会提前求值参数,还破坏了str_c()原本的向量化拼接逻辑,不够优雅。
解决方案1:使用tidyverse工具链(rlang + purrr)
利用rlang::dots_list()捕获未求值的...参数,再用purrr::map()逐个对每个输入向量应用替换逻辑,最后通过do.call()传递给str_c():
library(stringr) library(rlang) library(purrr) str_c_with_replace <- function(..., pattern = "z", replacement = "0") { # 捕获...参数,保留延迟求值特性,同时处理参数冲突等问题 input_dots <- dots_list(..., .homonyms = "error", .check_assign = TRUE) # 对每个输入向量单独执行替换 processed_dots <- map(input_dots, ~str_replace_all(.x, pattern, replacement)) # 将处理后的参数列表传递给str_c do.call(str_c, processed_dots) } # 测试示例 str_c_with_replace('az', 'bz', 'cz') # 输出:"a0b0c0" str_c_with_replace(c('az', 'zz'), 'bz') # 输出:"a0b0" "z0b0"(符合str_c的向量化拼接逻辑)
说明
dots_list()相比基础R的list(...),能更严谨地保留参数的延迟求值状态,还能处理参数重名、赋值表达式等异常情况;map()确保每个输入向量被单独处理,不会合并多个向量,完全匹配str_c()的输入要求;do.call()将处理后的参数列表以原始参数的形式传递给str_c(),完美保留原函数的所有行为。
解决方案2:仅使用基础R实现
如果不想依赖tidyverse包,可以用substitute()捕获未求值的...参数,再用lapply()逐个求值并处理:
library(stringr) str_c_with_replace <- function(..., pattern = "z", replacement = "0") { # 捕获未求值的...参数列表 input_dots <- as.list(substitute(list(...)))[-1] # 逐个求值并执行替换 processed_dots <- lapply(input_dots, function(expr) { str_replace_all(eval(expr, envir = parent.frame()), pattern, replacement) }) # 传递给str_c do.call(str_c, processed_dots) } # 测试示例 str_c_with_replace('az', 'bz', 'cz') # 输出:"a0b0c0" str_c_with_replace(c('az', 'zz'), 'bz') # 输出:"a0b0" "z0b0"
说明
substitute(list(...))获取未求值的参数表达式,[-1]是去掉返回列表中的第一个元素(即list本身);eval(expr, envir = parent.frame())确保参数在函数的父环境中求值,符合R的常规作用域规则;- 同样通过
lapply()保证每个输入向量被单独处理,不破坏str_c()的向量化逻辑。
为什么原方案不够优雅?
原方案中unlist(list(...))会把所有输入向量合并成一个单一向量:
- 提前强制求值了所有
...中的参数,若参数是延迟计算的表达式(比如未求值的函数调用),会失去延迟求值的特性; - 破坏了
str_c()的向量化拼接逻辑:当输入多个长度相同的向量时,str_c()原本会对应位置的元素拼接,而合并后会变成逐个拼接所有元素,结果不符合预期。
内容的提问来源于stack exchange,提问作者Matan Hakim
相关产品推荐
相关产品推荐

