为什么在R语言中,使用substitute替换noquote文本会变成字符串?

13

我想回答一个关于plotmath的问题,但我没能得到我想要的substitute输出。 我想要的输出:paste("Hi", paste(italic(yes),"why not?"))
而我得到的是:paste("Hi", "paste(italic(yes),\"why not?\")")

text<-'paste(italic(yes),"why not?")'
text
[1] "paste(italic(yes),\"why not?\")"
noqoute_text<-noquote(text)
noqoute_text
[1] paste(italic(yes),"why not?")
sub<-substitute(paste("Hi",noqoute_text),
           env=list(noqoute_text=noqoute_text))
sub
paste("Hi", "paste(italic(yes),\"why not?\")")

你可以尝试在最后一次粘贴后应用noquote。 - Nar
2个回答

13
您使用了错误的函数,请改用parse而不是noquote:
text<-'paste(italic(yes),"why not?")'
noquote_text <- parse(text=text)[[1]]

sub<- substitute(paste("Hi",noquote_text),env=list(noquote_text= noquote_text))
# paste("Hi", paste(italic(yes), "why not?"))

noquote 只是将特定的 print 方法应用于类型为 character 的对象,并赋予一个 class,以便不显示引号。

str(noquote("a"))
Class 'noquote'  chr "a"
unclass(noquote("a"))
[1] "a"
请详细说明您的答案?
在R中,您应该注意对象内部的内容和打印出来的内容之间的区别。 noquote 的作用是:
  • 将 "noquote" 添加到对象的类属性中
  • 仅此而已
代码如下:
function (obj) 
{
    if (!inherits(obj, "noquote")) 
        class(obj) <- c(attr(obj, "class"), "noquote")
    obj
}

那么当您打印它时,print.noquote 方法:

  • 如果存在,从对象中删除类 "noquote"
  • 使用参数 quote = FALSE 调用 print
  • 就这样

您实际上也可以在字符串上调用 print.noquote

print.noquote("a")
[1] a

它的打印方式类似于quote(a)substitute(a),但它是完全不同的东西。

在你尝试的代码中,你替换了一个字符串而不是一个调用。


1
这假设您想要一个调用作为输出。如果您想要一个未引用的字符串,我将不得不进行微调。 - moodymudskipper
请您详细说明一下您的答案,这将有助于我从您那里学到更多。 - Iman
我不确定它是否回答了所有问题。如果你想更好地了解替换,最好看看其他问题或提出新问题。如果你想了解这个案例的具体情况,请在这里告诉我,我会在几天内更新。 - moodymudskipper

4
为了解决这个问题,我认为Moody_Mudskipperss的答案很好,但是你要求一些详细说明...
你需要注意在R中类似外观的东西以不同的方式存储,这意味着它们的行为不同。尤其是plotmath处理标签的方式,因为它们试图模拟通常处理character字符串的方式,但再应用自己的规则。我认为你混合了以下3种事物:
  • character()是最熟悉的:只是一个字符串。打印时可能会令人困惑,因为引号等被转义。函数noquote基本上告诉R标记它的参数,以便引号不被转义。
  • 调用是“未计算的函数调用”:它是指R应该做什么的指示,但尚未执行。此调用中的任何错误尚未出现,您可以检查它。
    请注意,调用没有自己的环境,这意味着如果在函数内部从中计算,调用可能会产生不同的结果。
  • 表达式类似于调用,但应用更广泛,即不总是需要执行的函数。表达式可以是变量名,也可以是简单的值,例如“为什么不呢?”此外,表达式可以由多个单元组成,就像{}所示。
不同的函数可以在这些类之间进行转换,但有时函数(例如paste!)也会意外转换:
  • noquote没有太多有用的东西,正如Moody_Mudskipper已经指出的那样:它只改变了打印。但对象基本上仍然是字符。
  • substitute不仅替换变量,而且还将其第一个参数转换为(通常)调用。在这里,print会让您感到困扰,因为在打印调用时,其成员的特殊类别并未考虑在内。试一试:sub[[3]]从问题中给出
    [1] paste(italic(yes),"why not?")
    没有任何反斜杠!只有在打印完整的调用时,noquote部分才会丢失。
  • parse用于将字符转换为表达式。尚未计算任何内容,但引入了一些结构,因此您可以操作表达式。
  • paste通常会表现得很恼人(虽然如文档所述),因为它只能将字符字符串粘合在一起。因此,如果你给它除字符之外的任何东西,它会首先调用as.character。所以,如果你给它一个调用,你只会得到一个文本行。因此,在您的问题中,即使您使用parse,一旦开始将事物粘合在一起,您仍然会得到引号。
最后,你的问题更加困难,因为它使用了plotmath的内部逻辑。这意味着,一旦你尝试评估你的文本,你可能会得到一个错误“找不到函数italic”(或者如果有另外一个定义了italic函数的话,会得到更令人困惑的错误)。在plotmath中提供它可以工作,因为调用只由plotmath评估,它将给出一个良好的环境,其中italic按预期工作。
所有这些都意味着你需要将其全部视为表达式或调用。只要不能进行评估(只要是你处理表达式,而不是plotmath),它就需要保持为表达式或调用。给substitute一个调用可以工作,但你也可以更接近R中发生的情况。
call('paste', 'Hi', parse(text=text)[[1]])

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