在错误消息中获取变量?

5
这是我的代码:
test <- function(y){
irisname <- c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width","Species")
  if(y %in% irisname){
    print(y)
  } else{
    test <- function(...) stop("dummy error")
    test(y)
  }
}
> test("ds")
  Error in test(y) : dummy error 

在结果中:"Error in test(y) : dummy error ",我需要在test("ds")中使用"ds",而不是test(y)。
我该怎么做呢?
2个回答

8
这个几乎可以完成(多了一个冒号……),通过使用call.=FALSE来抑制关于调用的信息并将其嵌入错误消息中进行黑客攻击。 更新:为错误#1添加引号;更详细地解释了为什么这个问题很难。
我不知道您代码的结构,但是如果将对象传递到更深层次的结构中,您会使自己的生活变得更加困难。 直接从第一级内部调用stop(),或直接在您的错误消息中使用y中携带的信息,会更容易些。
test <- function(y,stop=FALSE){
   irisname <- c("Sepal.Length","Sepal.Width",
       "Petal.Length","Petal.Width","Species")
   if (stop) stop(sprintf("premature stop: var %s",y))
   if(y %in% irisname){
       print(y)
   } else{
     test <- function(...) {
         stop(sprintf("in test(\"%s\"): dummy error",...),
               call.=FALSE)
     }
     test(y)
 }
}

test("junk")
## Error: in test("junk"): dummy error
test("junk",stop=TRUE)
## Error in test("junk", stop = TRUE) : premature stop: var junk
test("junk")的输出中有一个多余的冒号需要去掉,这会相当的困难,因为Error:字符串在R中是硬编码的。你最好的选择可能是打印自定义的错误消息并静默停止或重新创建stop()的行为而不生成消息(参见?condition:例如return(invisible(simpleError("foo"))))。但是,你将不得不跳过很多麻烦才能做到这一点,并且很难确保你获得与stop()完全相同的行为(例如,错误消息是否已保存在错误消息缓冲区中?)
你想做的事情可能可以通过足够的修改R内部实现,但是在我看来,这么难还不如重新思考问题...
祝你好运。

谢谢Ben。不过,我还需要更多帮助。我的问题关键在于如何将变量放入错误信息中。有两个要求:1. 错误消息的格式为:部分1:部分2。2. 在部分1中(我认为R可以做到),消息将是Error in test("xx")。注意引号!非常感谢你的帮助。 - John
本,简单点。我想要的只是将值放入变量y中,在错误消息“Error in test(y): dummy error”中按此格式。我认为这可以很容易地完成,因为我已经在某些材料中看到过这个问题,而没有任何额外的解释。也许我的代码有一些逻辑错误。当我找到答案时,我会分享确切的过程。无论如何,谢谢。^_^ - John
我已经想通了。 只需使用以下代码:if(y %in% irisname){ print(y) } else{ stop("dummy error") }> test("ds") Error in test("ds") : dummy error 谢谢!@Ben @Richard - John

4

在函数的开始处,您可以检查参数。使用match.arg可能会很方便,或者您可以打印自定义消息并返回NA。

以下有两个更新

> test <- function(y)
  {
    if(!(y %in% names(iris))){
      message(sprintf('test("%s") is an error. "%s" not found in string', y, y))
      return(NA) ## stop all executions and exit the function
    }
    return(y)  ## ... continue
  }

> test("Sepal.Length")
# [1] "Sepal.Length"
> test("ds")
# test("ds") is an error. "ds" not found in string
# [1] NA

添加/编辑:当函数进入else语句时,您为什么要嵌套一个函数呢?我将其删除后,现在遇到以下问题。看起来您只是检查了一个参数,而最终用户(和RAM)希望立即得知是否输入了不正确的默认参数。否则,您会调用不必要的作业并在不需要的情况下使用内存。

test <- function(y){
     irisname <- c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width","Species")
     if(y %in% irisname){
         print(y)
     } else{
         stop("dummy error")
     }
 }
> test("ds")
# Error in test("ds") : dummy error
> test("Sepal.Length")
# [1] "Sepal.Length"

您也可以使用pmatch,而不是match.arg,因为match.arg会打印默认错误。
> test2 <- function(x)
  {
      y <- pmatch(x, names(iris))
      if(is.na(y)) stop('dummy error')
      names(iris)[y]
  }
> test2("ds")
# Error in test2("ds") : dummy error
> test2("Sepal.Length")
# [1] "Sepal.Length"

1
我的答案更接近OP的要求,但我认为你的更接近他们应该做的事情。 - Ben Bolker
@John,我有点困惑你的评论。请注意,在 > test("ds") 中,ds 在两个实例中都被引用了。我不确定你到底想要什么。如果可以的话,请写一行带有您想要的确切错误信息。 - Rich Scriven
1
为什么他们不能在参数检查时使用 stop('dummy error') 停止程序? - Rich Scriven
1
我不知道。恐怕他们有一些逻辑没有向我们展示,为什么他们想要在进一步的函数调用层中嵌入 stop(),但从他们给我们的内容中无法判断。这就是为什么我说我认为他们应该遵循你的结构(我的答案试图保持他们问题中显示的结构,但未能获得他们想要的精确错误字符串)。 - Ben Bolker
1
@John,很高兴你解决了它。你有没有注意到我上面的第二个函数就是这样的? - Rich Scriven
显示剩余7条评论

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