首页 > 解决方案 > 在用户在 ruby​​ 中输入有效输入之前,如何请求用户输入?

问题描述

这是一个问题,他们要求我添加一个额外的 if 语句,以在用户不输入任何内容时重新提示用户输入。

我尝试使用while循环,但仍然无法解决问题

print "please enter a sentence with a letter s"

while user_input = gets.chomp.downcase! 
  case user_input
  when user_input.include? "s"
    user_input.gsub(/s/,"th")
    print "Daffy Duck says #{user_input}"
    break
  else
    print "please enter a sentence with a letter s"
  end 

我希望“请输入带有字母 s 的句子”循环,直到用户输入字母“s”

标签: rubywhile-loop

解决方案


我的理解是,用户输入句子,直到一个包含一个"s"或一个"S",然后采取某种行动并且程序终止。

让我们来看看你有什么。

print "Please enter a sentence with a letter s"

我认为你想要puts,它添加了一个换行符,而不是print,它没有。

while user_input = gets.chomp.downcase!

假设用户输入"Cat"(即使它不是一个句子),然后按下 Enter 键,然后

str0 = gets
  #=> "Cat\n"
str1 = str0.chomp
  #=> "Cat"
user_input = str1.downcase!
  #=> "cat"
str1
  #=> "cat"
user_input
  #=> "cat"

所以我们有

while "cat"

由于"cat"既不是false也不是nil(唯一的逻辑false对象),这与

while true

因此执行移至while循环内的第一条语句。假设用户输入"cat"并按下 Enter 键。然后

str0 = gets
  #=> "cat\n"
str1 = str0.chomp
  #=> "cat"
user_input = str1.downcase!
  #=> nil
str1
  #=> "cat"
user_input
  #=> nil

所以程序不会进入while循环!你问,如何才能"cat".downcase返回nil?查看String#downcase 的文档!. 它显示nil如果没有要小写的字符则返回。Ruby 有许多方法可以做同样的事情:如果接收者没有改变nil,则返回。(在您的教育阶段不要被“为什么”所困扰。)目前建议您避免使用bang方法(以 结尾"!")。

同样,如果用户没有输入任何内容并按下回车键,

str1 = "\n".chomp
  #=> "" (an empty string)
user_input = str1.downcase
  #=> nil

"".downcase!nil出于同样的原因返回"cat".downcase!

我想你这里是什么。

user_input = gets.chomp
while !user_input.match?(/s/i)

/s/i是一个正则表达式,用于确定字符串是否包含一个"s"或一个"S"iin/i是一个不区分大小写的修饰符。(可以改为写while user_input !~ /s/i。)

while循环中的第一条语句是

  case user_input

case有参数时(此处user_input),when语句包含作为参数可能值的case参数,例如

  case user_input
  when "call me silly!"
    puts "You are silly"
  when...

你不是在这里这样做,所以你想case单独一行:

case
when user_input == ...
  ...
end

但是,这里不需要循环中的 case 语句或“if/elsif/else/end”构造,因为我们已经确定它user_input不包含“s”。我们在循环中需要的是:

while !user_input.match?(/s/i)
  puts "Please enter a sentence with a letter s"
  user_input = gets.chomp
end

循环终止后user_input是一个包含“s”的字符串。因此,我们只需要执行以下操作。

puts "Daffy Duck says #{user_input}"
  #=> "Quack, quack, quackity-quack, sir"

请注意,您的声明

user_input.gsub(/s/, "s")

用“s”替换每个“s”。:-) 也不需要break关键字。

把所有这些放在一起,你可以写:

puts "Please enter a sentence with a letter s"
user_input = gets.chomp
while !user_input.match?(/s/i)
  puts "Please enter a sentence with a letter s"
  user_input = gets.chomp
end
puts "Daffy Duck says #{user_input}"

你以为我完了。没那么快!

首先,许多 Ruby 程序员试图避免诸如此类的否定while !user_input.match?(/s/i)(尽管这纯粹是个人喜好问题)。你可以改为写那行

until user_input.match?(/s/i)

一个更重要的问题是代码的复制。您可以通过使用Kernel#loop和关键字break而不是whileor来改进它until

loop do
  puts "Please enter a sentence with a letter s"
  user_input = gets.chomp
  if user_input.match?(/s/i)
    puts "Daffy Duck says #{user_input}"
    break
  end
end

但是,如果我们写

loop do
  puts "Please enter a sentence with a letter s"
  user_input = gets.chomp
  break if user_input.match?(/s/i)
end
puts "Daffy Duck says #{user_input}"

最后一行会引发异常

NameError (undefined local variable or method `user_input' for main:Object)

因为变量user_input只在循环中定义。

我通常使用loopandbreak而不是whileor until


推荐阅读