是否可以在不需要用户按Enter的情况下使用R函数阅读行?

时间:2019-07-11 13:02:15

标签: r user-input

我正在编写一个需要用户输入的小函数,该函数已经使用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')
     } 
 }
}

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

2 个答案:

答案 0 :(得分:1)

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")))。这使得在已知输入长度超过一个字符的情况下使用此方法变得可行。

答案 1 :(得分:0)

编辑:预先,这在RStudio中也不起作用。由于我确信RStudio确实拦截并控制了很多R,尽管import android.content.Context import android.util.Log import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import kotlinx.coroutines.CancellationException import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope class TestWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { companion object { private const val TAG = "TestWorker" } override suspend fun doWork(): Result { return coroutineScope { val job = async { someWork() } job.invokeOnCompletion { exception: Throwable? -> when(exception) { is CancellationException -> { Log.e(TAG, "Cleanup on completion", exception) // cleanup on cancellations } else -> { // do something else. } } } job.await() } } suspend fun someWork(): Result { TODO() } } 可能有其他控制方法(例如C_menu),但我认为RStudio正在拦截按键(从而强制 options-使用)。因此,我建议这倾向于使用RStudio进行错误/功能请求。


如果您查看<enter>的来源,您将在最后看到它的来源:

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 exit\n")) } 函数(未导出)可以(用于)执行您想要的操作。我不知道该功能的内部运作方式,因此有一些经验性的总结/观点:

  • 通常(但并非总是[1]),C_menu循环中的第一遍需要输入一个回车;
  • 在第一个repeat之后,单位整数似乎少<enter>,其他任何东西都支持任意长度,并且需要<enter>
<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)。

不确定您是否可以使此过程适应该问题,因为它似乎仅限于一位数字(一旦您超过了第一个条目)。我还没有找到它的来源,看看是否有一个带有其他参数的伴随函数。

注意:

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