我正在编写一个需要用户输入的小函数,我已经为使用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
)。
不确定您是否可以调整您的流程以适应此,因为它似乎仅限于个位数(一旦您通过了第一个条目)。我还没有找到它的来源,看看是否有带有其他参数的配套函数。
笔记:
- 我很少可以在第一次使用时获取代码来处理无输入条目,不确定这是我的代码编辑(emacs/ess)还是其他问题。如果是这样,则可能是某个地方的错误。