我正在撰写一个包含if
和else
的练习计划。代码如下:
puts "What is your name?"
user_name = $stdin.gets.chomp
print "Hello #{user_name}! Welcome to Puzzles and Riddles v.1!"
puts "There are two doors \n 1. Riddles \n 2. Puzzles. \n Which door do you go through?"
answer_1 = $stdin.gets.chomp
if
answer_1 == "1"
puts "You have taken the Riddle room!"
print "Here is your riddle: \n You use a knife to slice my head and weep beside me when I am dead. \n What am I?"
end
riddle_1_answer = $stdin.gets.chomp
if
riddle_1_answer == ( riddle_1_answer == "An onion" ) || ( riddle_1_answer == "an onion" ) || ( riddle_1_answer == "Onion" ) || ( riddle_1_answer == "onion" )
puts "The correct answer is: An onion! \n You have advanced to round two."
else
puts "Sorry, your answer is incorrect. Think about it."
end
puts "Riddle 2. \n What has 4 fingers and a thumb, but is not living?"
riddle_2_answer = $stdin.gets.chomp
现在,如果用户错误riddle_1_answer
我将如何制作,以便程序退出/中止?
我尝试将exit(0)添加到else部分,它将终止程序,但也会出现错误。所以我不确定错误是导致程序结束还是退出(0)命令
答案 0 :(得分:0)
从您的问题,示例代码以及您对@AndrewMarshall的回答中可以明显看出,您需要一些指导。
你走了。
首先,ruby是众多编程语言中的一种,并且有许多经验丰富的程序员最终倾向于它的原因:ruby是面向对象的,富有表现力的,强大的,并且相当简洁而不是不自然的简洁。所以,如果你要学习红宝石,可以通过阅读大量优秀的红宝石代码来学习,从中学习良好实践。
其次,外观很重要,因为它会影响或增强可读性和理解力。良好的外观有助于提高可读性和更快速的理解。一个糟糕的外表恰恰相反。
代码中if
,else
和end
令牌的对齐情况不佳;它使得很难看到代码逻辑的结构。
编程中有许多经验法则。以下是一些适用于大多数语言的规则:
因此,让我们将这两个原则应用到您的代码中并对其进行一些转换。
前两行:
puts "What is your name?"
user_name = $stdin.gets.chomp
错误是否可以接受? STDIN上的EOF返回nil
,这会导致chomp
出错。
是否可以接受空字符串(零长度)名称?如果没有,我们应该怎么做呢?
当做一些相对简单的事情很复杂时,例如获取用户名,将复杂性封装在函数或方法中,因此需要用户名的代码不会因为获取它的复杂性而变得混乱。
这是一个替代品。首先,让我们管理在一个小函数中获取用户名的细节(和复杂性)。
def get_user_name
name = ''
while name.size == 0 do
print "What is your name? "
name = gets
exit(1) if name.nil? # exit program on EOF
name.strip!
end
name
end
请注意,我们不会在chomp
上使用name
,直到我们确定它不是nil
为止。许多程序通过退出,中止或继续对EOF的输入作出反应而没有任何其他问题。在这个例子中,我们假设用户想要退出。
另请注意,我们使用的是strip!
而不是chomp!
?这是因为strip!
将删除前导空格和尾随空格,包括尾随换行符。
另请注意,我们没有使用$stdin.gets
,而只是使用gets
?这是因为gets
的默认对象是$stdin
。
在小函数(方法)中管理异常情况的更好方法可能是raise
异常,让更高级别的应用程序逻辑决定如何管理它。考虑到这一点,这是一个修订的定义:
def get_user_name
name = ''
while name.size < 1 do
print "What is your name? "
name = gets
raise "End of input" if name.nil? # raise exception on EOF
name.strip!
end
name
end
现在,定义了get_user_name
,我们可以在需要用户名的任何地方使用它。我们知道EOF是管理的,我们知道我们不会得到一个空字符串。
user_name = get_user_name
现在,让我们执行原始代码的其余部分,但要正确对齐和缩进。
print "Hello #{user_name}! Welcome to Puzzles and Riddles v.1!"
puts "There are two doors \n 1. Riddles \n 2. Puzzles. \n Which door do you go through?"
answer_1 = $stdin.gets.chomp
if answer_1 == "1"
puts "You have taken the Riddle room!"
print "Here is your riddle: \n You use a knife to slice my head and weep beside me when I am dead. \n What am I?"
end
riddle_1_answer = $stdin.gets.chomp
if riddle_1_answer == ( riddle_1_answer == "An onion" ) || ( riddle_1_answer == "an onion" ) || ( riddle_1_answer == "Onion" ) || ( riddle_1_answer == "onion" )
puts "The correct answer is: An onion! \n You have advanced to round two."
else
puts "Sorry, your answer is incorrect. Think about it."
end
puts "Riddle 2. \n What has 4 fingers and a thumb, but is not living?"
riddle_2_answer = $stdin.gets.chomp
现在对齐和缩进是正确的,它更容易看到逻辑及其缺陷。它也更容易看到逻辑模式,每当你看到一个模式,然后干掉它,并制作方法(函数)来封装重复。
但首先,让我们解决明显的错误。
if
表达式已被破坏。再看一遍,你会看到这个:
if riddle_1_answer == TEST1 || TEST2 || TEST3 || TEST4
我已使用TEST
n 替换您所拥有的各种区分大小写的测试。
此if
表达式将始终失败,因为riddle_1_answer
的值永远不会为true
或false
并且各种TEST
n个表达式的结果将始终为true
或false
。我很确定你想要这个:
if TEST1 || TEST2 || TEST3 || TEST4
其次,在测试字符串值时,没有必要测试所有案例变体。只需downcase
答案并测试小写测试值(除非区分大小写非常重要)。或者,如果简单的字符串测试不够,则使用regular expression
并使用i
选项进行不区分大小写的匹配。例如:
if riddle_1_answer =~ /(?:an )?onion/i
将在大写,小写和混合大小写中测试"an onion"
或"onion"
。
或许比这些小错误更重要,人们应该避免重复。一般模式似乎是:
当你看到这样的事情时,你应该开始考虑数组和哈希。当值可以用数字索引时使用数组,当你想获得与变化键相关的值时使用散列。然后,可以使用一个简单的循环来迭代数组或散列的值。
因此,看到上面的模式,我们需要一种方法来提示问题,得到答案,处理可能的EOF和空字符串,验证非空答案,可能重复问题和放大器,这一点变得更加清晰。 ;在需要时回答。
因此,让我们定义一个方法来获得答案
# prompt_and_get_answer PROMPT, ANSWERS_DATA
#
# issue PROMPT, and get an answer, which must be one of the
# values in ANSWERS_DATA array, or one of the keys of the
# ANSWERS_DATA hash.
def prompt_and_get_answer prompt, answers_data
ans = ''
while ans.size < 1
print prompt
ans = $stdin.gets
if ans.nil?
raise "End of input"
end
ans.strip!
if answers_data.class == Hash # hash?
answers = answers_data.keys.sort
else
answers = answers_data.sort
end
matches = answers.grep(/#{ans}/i) # match possible valid answers
case matches.size # how many items found?
when 0
puts "#{ans} is not a valid answer. Use one of:"
puts answers.join(', ')
ans = ''
when 1 # return the match or the value of the matching key
ans = answers_data.class == Hash ? answers_data[matches[0]] : matches[0]
else
puts "#{ans} is ambiguous; be more specific to match one of:"
puts answers.join(', ')
ans = ''
end
end
ans
end
现在,我们可以使用此方法将提示作为参数,并获得答案,因为它知道它不会是一个空答案,而且它不会是一个EOF。< / p>
首先,让我们为问题命名,然后让我们显示输出中显示的提示,而不使用明确转义的换行符(\n
)。
$prompt1 = <<EOQ
There are two doors
1. Riddles
2. Puzzles
Which door do you go through?
EOQ
$answer1 = [ '1', '2' ]
$prompt2 = <<EOQ
Here is your riddle:
You use a knife to slice my head and weep beside me when I am dead.
What am I?
EOQ
$answer2 = [ 'onion' ]
ans1 = prompt_and_get_answer $prompt1, $answer1
if ans1 == '1'
do_riddles
elsif ans1 == '2'
do_puzzles
else
raise "Bad answer to prompt1"
end
def do_riddles
while true
ans = prompt_and_get_answer $prompt2, $answer2
if ans == 'onion'
puts "yay! you're right!"
break
else
puts "nope. Try again"
end
end
end
您可以从中看到,我们已经使用方法(函数)将逻辑分解为更小的部分,并将获得答案的细节与测试它们的细节分开。
稍后,我们可以看到如何使用表格和哈希来建立问题列表。
祝你好运。