我正在尝试替换 R 表达式中的字符(而不是字符串中的字符),但似乎替换字符的常用函数在这种情况下不起作用。例如,给定以下情况:
exp <- expression(italic(N[T]))
class(exp) # "expression"
Run Code Online (Sandbox Code Playgroud)
和string::str_replace都base::gsub无法转换此表达式对象中的字符。第一个返回警告消息,并且在两种情况下都返回“字符”类的对象:表达式对象丢失。
exp %>% stringr::str_replace(pattern = "T", replacement = "i")
Run Code Online (Sandbox Code Playgroud)
[1]“斜体(N[i])”
警告消息:在 stri_replace_first_regex(string,pattern,fix_replacement(replacement), 中:参数不是原子向量;强制
exp %>% base::gsub(pattern = "T", replacement = "i")
Run Code Online (Sandbox Code Playgroud)
[1]“斜体(N[i])”
是否可以在不丢失类类型的情况下转换表达式中的字符?
像下面这样的技巧是行不通的:
exp %>% base::gsub(pattern = "N", replacement = "i") %>% base::gsub(pattern = "^", replacement ="expression(") %>% base::gsub(pattern = "$", replacement = ")")
Run Code Online (Sandbox Code Playgroud)
    1)替换转换为调用对象,使用substitute它然后转换回来(或者调用对象可能足以满足您的需求,并且不需要转换回表达式)。这完全在 R 语言级别工作,而不是字符串操作。
as.expression(do.call("substitute", list(exp[[1]], list(T = as.name("I")))))
## expression(italic(N[I]))
Run Code Online (Sandbox Code Playgroud)
2) 递归另一种方法是递归地遍历调用对象并将 T 替换为 I。请注意,这输入和输出一个调用对象,因此如果您需要使用表达式对象,请从表达式转换为调用对象,并从调用对象转换为表达式比调用对象。
T2I <- function(e) {
  if (identical(e, as.name("T"))) e <- as.name("I")
  else if (length(e) > 1) for(i in 1:length(e)) e[[i]] <- Recall(e[[i]])
  e
}
as.expression(T2I(exp[[1]]))
## expression(italic(N[I]))
Run Code Online (Sandbox Code Playgroud)
3) 赋值如果你知道 exp 的结构,那么这个赋值将会起作用:
exp.orig <- exp # in case you need to save the original
exp[[1]][[2]][[3]] <- as.name("I")
exp
## expression(italic(N[I]))
Run Code Online (Sandbox Code Playgroud)
4) 字符串操作此操作将转换为字符串、执行替换并转换回来。与另一个答案类似但不完全相同:
parse(text = gsub("\\bT\\b", "I", format(exp[[1]])))
## expression(italic(N[I]))
Run Code Online (Sandbox Code Playgroud)
5) rrapply rrapply 包中的  函数rrapply可以遍历表达式并执行替换。
library(rrapply)
condition <- function(x) x == as.name("T")
f <- function(x) as.name("I")
rrapply(exp, condition = condition, f = f, how = "replace")
## expression(italic(N[I]))
Run Code Online (Sandbox Code Playgroud)
添加rrapply解决方案。