使用STDIN.gets时出现多行输入问题

时间:2010-09-16 14:07:01

标签: ruby input stdin

看了this个问题后,我有以下代码:

$/ = "\0"
answer = STDIN.gets

现在,我希望这会让用户:

  • 输入多行输入,按 Ctrl-D 终止。
  • 输入单行输入,按 Ctrl-D 终止。
  • 输入“无”输入,按 Ctrl-D 终止。

然而,我实际看到的行为是:

  • 用户可以输入多行输入。
  • 用户可以输入单行输入,除非他们点击 Ctrl-D 两次。< / LI>
  • 如果用户立即点击 Ctrl-D ,则可以输入“无”输入。

那么,为什么单行情况(即如果用户输入了一些文本但没有换行,然后点击 Ctrl-D )则需要两次按 Ctrl-D ?如果用户什么都不输入,为什么它会起作用呢? (我已经注意到,如果他们没有输入任何内容并点击 Ctrl-D ,我没有得到一个空字符串但是nil类 - 我试图在结果上调用.empty?时发现了这个,因为它突然失败了。如果有办法让它返回一个空字符串,那就太好了。我更喜欢检查.empty?==,并不特别想要为nil类定义.empty?。)

编辑:由于我真的想知道在Ruby中执行此操作的“正确方法”,我将提供200个代表的赏金。我也会接受一些答案,这些答案可以通过合理的“提交”程序进入终端多行输入 - 我将成为'合适'的判断者。例如,我们目前正在使用两个“\ n”,但这不合适,因为它会阻止段落并且不直观。

2 个答案:

答案 0 :(得分:2)

从终端设备读取STDIN时,您正在以稍微不同的模式从文件或管道读取STDIN。

当从tty Control-D(EOF)读取时,如果输入缓冲区为空,则只发送EOF。如果它不为空,则将数据返回到读取系统调用,但不发送EOF。

解决方案是使用一些较低级别的IO并一次读取一个字符。以下代码(或类似的东西)将执行您想要的操作

#!/usr/bin/env ruby

answer = ""
while true
  begin
    input = STDIN.sysread(1)
    answer += input
  rescue EOFError
    break
  end
end

puts "|#{answer.class}|#{answer}|"

使用各种输入运行此代码的结果如下: -

INPUT 这是一行&lt; CR&gt;&lt; Ctrl-D&gt;

|String|This is a line
|

INPUT 这是一行&lt; Ctrl-D&gt;

|String|This is a line|

<强> INPUT &LT;按Ctrl-d取代;

|String||

答案 1 :(得分:2)

基本问题是终端本身。查看帖子右侧的许多相关链接。要解决这个问题,您需要将终端置于原始状态。以下在Solaris机器上为我工作:

#!/usr/bin/env ruby
# store the old stty settings
old_stty = `stty -g`
# Set up the terminal in non-canonical mode input processing
# This causes the terminal to process one character at a time
system "stty -icanon min 1 time 0 -isig"
answer = ""
while true
  char = STDIN.getc
  break if char == ?\C-d # break on Ctrl-d
  answer += char.chr
end
system "stty #{old_stty}" # restore stty settings
answer

我不确定是否需要存储和恢复stty设置,但我已经看到其他人这样做了。