Насколько я понимаю, пользователь вводит предложения до тех пор, пока одно из них не содержит "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"
.i
in /i
является модификатором case-индифферентности .(Вместо этого можно написать while user_input !~ /s/i
.)
Первое утверждение в цикле while
это
case user_input
Когда case
имеет аргумент (здесь user_input
), *Операторы 1071 * содержат аргументы, которые являются возможными значениями аргумента 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
вместо while
или 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
определяется только в цикле.
Я обычно использую loop
и break
предпочтительнее while
или until
.