我在Scala中为一个使用文本输入和输出的游戏编写机器人。所以我希望以交互方式处理一个进程 - 也就是说,我的代码接收进程的输出,使用它,然后才将其下一个输入发送到进程。所以我想同时给一个函数访问inputStreams和outputStream。
这似乎不适合scala.sys.process.BasicIO中的任何工厂或scala.sys.process.ProcessIO的构造函数(三个函数,每个函数只能访问一个流)
这是我现在的表现。
private var rogue_input: OutputStream = _
private var rogue_output: InputStream = _
private var rogue_error: InputStream = _
Process("python3 /home/robin/IdeaProjects/Rogomatic/python/rogue.py --rogomatic").run(
new ProcessIO(rogue_input = _, rogue_output = _, rogue_error = _)
)
try {
private val rogue_scanner = new Scanner(rogue_output)
private val rogue_writer = new PrintWriter(rogue_input, true)
// Play the game
} finally {
rogue_input.close()
rogue_output.close()
rogue_error.close()
}
这很有效,但它并不像Scala那样。有没有更惯用的方法呢?
答案 0 :(得分:1)
所以我想以交互方式处理一个进程 - 也就是说,我的代码接收进程的输出,使用它,然后才将其下一个输入发送到进程。
一般来说,这传统上由expect解决。存在受expect
启发的各种语言的库和工具,包括Scala:https://github.com/Lasering/scala-expect。
项目的自述文件提供了各种示例。虽然我不确切知道rouge.py
/ stdin
互动对stdout
}的期望,但这里有一个快速的“hello world”示例,展示了如何与Python解释器进行交互(使用Ammonite REPL,具有方便的库导入功能):
import $ivy.`work.martins.simon::scala-expect:6.0.0`
import work.martins.simon.expect.core._
import work.martins.simon.expect.core.actions._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
val timeout = 5 seconds
val e = new Expect("python3 -i -", defaultValue = "?")(
new ExpectBlock(
new StringWhen(">>> ")(
Sendln("""print("hello, world")""")
)
),
new ExpectBlock(
new RegexWhen("""(.*)\n>>> """.r)(
ReturningWithRegex(_.group(1).toString)
)
)
)
e.run(timeout).onComplete(println)
上述代码的作用是“预期”>>>
被发送到stdout
,当它发现时,它会发送print("hello, world")
,然后是换行符。从那时起,它会使用正则表达式读取并返回所有内容,直到下一个提示符(>>>
)。
在其他调试信息中,上述内容应导致Success(hello, world)
打印到您的控制台。
图书馆有各种其他风格,也可能还有其他类似的图书馆。我的主要观点是,expect
灵感的图书馆很可能是您正在寻找的。 p>