是否可以使用 R 函数读取行而无需用户按回车键?



我正在编写一个需要用户输入的小函数,我已经为使用readline函数编写了代码,但希望消除用户在响应控制台中的提示后按 [Enter ] 的需要。

我在SO上进行了广泛的搜索,但没有找到解决方案,readline文档也没有提供任何潜在的解决方案。

timer <- function() {
require(tictoc) #load required package
experiment_no <- readline("Experiment number: ")
while(T){       #open infinite while loop
tic()       #start timer
input_state=readline("State input: ")  #allow for entry of state
if(input_state %in% 1:5){    #check if it's acceptable 
elapsed=toc()            #if it is then end timer and record data
write.table(cbind(experiment_no,input_state,elapsed$toc-elapsed$tic),'results.txt',col.names=F,row.names=F,quote=F,append=T)
}else if(input_state=='t'){  #if input is 't' 
break                    #break out of while loop
}else if(input_state <1 | input_state > 5 & input_state!='t'){#if input is not and accepted state AND is not 't'
print('thats not an allowed state- please try another')
} 
}
}

我希望用户能够在不按回车键的情况下将实验编号输入控制台。

与 r2evans 的响应相反,此解决方案仅适用于 RStudio。它依赖于 rstudioapi 包捕获控制台中当前输入的能力。

dynamic_readline <- function() {
while (rstudioapi::isAvailable()) {
input <- rstudioapi::getConsoleEditorContext()$contents
if (input != "") {
rstudioapi::sendToConsole("", execute = FALSE)
return(input)
}
Sys.sleep(0.1)
}
readline()
}

while循环每 0.1 秒检查一次控制台的内容,如果输入了任何内容,则返回输入。如果检测到某些内容,它会将""发送到控制台以清除它。如果 rstudioapi 不可用(即编辑器不是 Rstudio),函数将回退到readline()

睡眠时间可以根据您需要的响应时间进行调整,尽管在 R 控制台中您不会获得 60 Hz 的游戏玩法。

您还可以调整if语句以使用%in%而不是!=来测试特定的有效输入,而不是任何非空输入。(类似于if (input %in% c("w", "a", "s", "d", "quit")))。这使得将此方法用于长度超过一个字符的已知输入是可行的。

编辑:预先,这也不适用于RStudio。由于我相信 RStudio 确实拦截和控制了相当多的 R,而C_menu可能还有其他控制方法(例如,options),我认为 RStudio 更有可能拦截按键(从而强制<enter>使用)。有了这个,我建议这倾向于 RStudio 的错误/功能请求。


如果您查看utils::menu的源代码,您将在最后看到它确实如此:

repeat {
ind <- .Call(C_menu, as.character(choices))
if (ind <= nc) 
return(ind)
cat(gettext("Enter an item from the menu, or 0 to exitn"))
}

这表明C_menu函数(未导出)可以(ab)用于执行您想要的操作。我不知道函数的内部工作原理,所以一些经验要点/警告:

  • 通常(但并非总是[1]),repeat循环中的第一次通过需要输入任何条目;
  • 在第一个<enter>之后,对于个位数整数来说,它似乎<enter>-less,其他任何东西都支持一些任意长度并需要<enter>
repeat {
ret <- .Call(utils:::C_menu, letters)
if (ret == 0L) break
cat("    you entered ", ret, "n")
}
# Selection: 345            # I typed "345<enter>"
#     you entered  345 
# Selection: 3              # just "3", no enter
#     you entered  3 
# Selection: 4
#     you entered  4 
# Selection: 5
#     you entered  5 
# Selection:                # just enter
#     you entered  27 
# Selection: C              # "C<enter>"
#     you entered  27 
# Selection: c              # "c<enter>"
#     you entered  3 
# Selection: abc            # "abc<enter>"
#     you entered  27 
# Selection: 0              # just "0", no enter, it quits

我推断27意味着我输入了原始选择中没有的内容(letters)。

不确定您是否可以调整您的流程以适应此,因为它似乎仅限于个位数(一旦您通过了第一个条目)。我还没有找到它的来源,看看是否有带有其他参数的配套函数。

笔记:

  1. 很少可以在第一次使用时获取代码来处理无输入条目,不确定这是我的代码编辑(emacs/ess)还是其他问题。如果是这样,则可能是某个地方的错误。

相关内容

  • 没有找到相关文章

最新更新