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

发布于 2024-09-24 04:39:09 字数 1011 浏览 0 评论 0原文

看过这个问题后,我有以下问题代码:

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

现在,我希望这将允许用户:

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

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

  • 用户可以输入多行输入。
  • 用户不能输入单行输入,除非他们按Ctrl-D两次
  • 如果用户立即按下 Ctrl-D,则可以输入“无”。

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

编辑:因为我真的很想知道“正确的为了在 Ruby 中做到这一点,我提供 200 个代表的赏金。我还将接受提供另一种通过合理的“提交”程序进入终端多行输入的方式的答案 - 我将成为“合适”的判断者。例如,我们当前使用两个“\n”,但这并不合适,因为它会阻塞段落并且不直观。

Having looked at this question, I have the following code:

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

Now, I was hoping that this would allow the user to:

  • enter a multi-line input, terminating by pressing Ctrl-D.
  • enter a single line input, terminating by pressing Ctrl-D.
  • enter a "nothing" input, terminating by pressing Ctrl-D.

However, the behaviour I actually see is that:

  • The user can enter a multi-line input fine.
  • The user can not enter a single line input, unless they hit Ctrl-D twice.
  • The user can enter a "nothing" input if they hit Ctrl-D straight away.

So, why does the single line situation (i.e. if the user has entered some text but no newline and then hit Ctrl-D) require two presses of Ctrl-D? And why does it work then if the user enters nothing? (I have noted that if they enter nothing and hit Ctrl-D, I don't get an empty string but the nil class - I discovered this when trying to call .empty? on the result, since it suddenly failed horribly. If there is a way to get it to return an empty string as well, that would be nice. I prefer checking .empty? to ==, and don't particularly want to define .empty? for the nil class.)

EDIT: Since I really would like to know the "correct way" to do this in Ruby, I am offering a bounty of 200 rep. I will also accept answers that give another way of entering terminal multi-line input with a sensible "submit" procedure - I will be the judge of 'suitable'. For example, we're currently using two "\n"s, but that's not suitable, as it blocks paragraphs and is unintuitive.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你是我的挚爱i 2024-10-01 04:39:09

基本问题是终端本身。请参阅帖子右侧的许多相关链接。为了解决这个问题,您需要将终端置于原始状态。以下内容在 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 设置,但我见过其他人这样做。

The basic problem is the terminal itself. See many of the related links to the right of your post. To get around this you need to put the terminal in a raw state. The following worked for me on a Solaris machine:

#!/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

I'm not sure if the storing and restoring of the stty settings is necessary but I've seen other people do it.

风情万种。 2024-10-01 04:39:09

从终端设备读取 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 这是一行

|String|This is a line
|

INPUT 这是一行

|String|This is a line|

输入

|String||

When reading STDIN from a terminal device you are working in a slightly different mode to reading STDIN from a file or a pipe.

When reading from a tty Control-D (EOF) only really sends EOF if the input buffer is empty. If it is not empty it returns data to the read system call but does not send EOF.

The solution is to use some lower level IO and read a character at a time. The following code (or somethings similar) will do what you want

#!/usr/bin/env ruby

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

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

The results of running this code with various inputs are as follows :-

INPUT This is a line<CR><Ctrl-D>

|String|This is a line
|

INPUT This is a line<Ctrl-D>

|String|This is a line|

INPUT<Ctrl-D>

|String||
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文