Ruby 零基础教程

Ruby 用户输入

在交互式程序中,与用户进行沟通的能力是基础。虽然像前面章节讲过的那样,读写文件可以让程序与持久化数据进行交互,但处理来自命令行的用户输入,则赋予了程序实时、动态交互的能力。这意味着你的程序可以在运行时提出问题、接收答案,并根据用户输入的内容调整自身的行为。这种能力是从编写简单的命令行工具到开发复杂交互式应用必不可少的一环,它能让你的 Ruby 程序比单纯处理预设数据的程序更加有趣且实用。

1. 使用 gets 接收输入

Ruby 提供了一个非常直接的方法来捕获用户的输入:gets。这个方法会从标准输入(通常是键盘)读取用户输入的一行文本,直到用户按下回车键 (Enter)。读取到的文本会作为一个字符串返回,其中包含了按下回车键时产生的换行符 (\n)。

1.1 gets 的基本用法

当程序调用 gets 时,它会暂停执行,等待用户输入内容并按下回车。一旦按下回车,gets 就会捕获截止到那一刻输入的所有内容。

puts "你叫什么名字?"
user_name = gets
# 程序将在这里暂停,等待用户输入。
# 如果用户输入 "Alice" 并按下回车,user_name 将存储 "Alice\n"。
puts "你好,#{user_name}!"
# 由于带有换行符,这行代码将输出 "你好,Alice\n!"。

在上面的例子中,如果用户输入 Alice 并按下回车,user_name 变量中包含的字符串将是 "Alice\n"。请注意末尾的 \n,这就是换行符。当 puts 尝试显示 user_name 时,它会打印出 "Alice",紧接着是这个额外的换行符,这会导致光标移动到下一行,随后 puts 自身又会加上一个换行符。这通常会造成多余的空行或排版错乱。

1.2 使用 chomp 移除换行符

为了解决不需要的换行符问题,Ruby 字符串提供了一个非常方便的方法:chompchomp 方法会从字符串的末尾移除记录分隔符(默认即为 \n),前提是它确实存在。在实际开发中,直接在 gets 后面链式调用 chomp 是非常常见的做法。

puts "你最喜欢的颜色是什么?"
favorite_color = gets.chomp
# 如果用户输入 "blue" 并按下回车,favorite_color 将只存储 "blue"。
# 末尾的 `\n` 字符被 `chomp` 移除了。
puts "你最喜欢的颜色是 #{favorite_color}。"
# 这将输出 "你最喜欢的颜色是 blue。" 不会产生多余的换行。

当你想要获取用户真实的输入内容,而不包含尾部的任何换行符时,使用 gets.chomp标准且规范的做法。它确保了输入字符串的纯净,便于后续处理,能够防止打印时出现布局问题或比较字符串时发生意外。

2. 将用户输入转换为不同数据类型

这里有一个需要牢记的关键点:gets 返回的永远是字符串。即使用户输入的是一个数字,程序接收到的也是字符串格式。对于许多操作(尤其是数学计算或比较大小),你需要将这种字符串输入转换成整数或浮点数等其他数据类型。

2.1 使用 to_i 转换为整数

如果你预期用户输入的是一个整数(Whole number),可以使用 to_i 方法将字符串进行转换。

puts "请输入你的年龄:"
age_as_string = gets.chomp
# 如果用户输入 "30",age_as_string 就是 "30"(一个字符串)。
age_as_integer = age_as_string.to_i
# age_as_integer 现在是 30(一个整数)。
puts "5 年后,你将是 #{age_as_integer + 5} 岁。"
# 这里将正确执行数学运算:30 + 5 = 35。

# 如果输入的内容不是有效的数字会发生什么?
puts "请输入一个数字:"
not_a_number = gets.chomp # 用户输入了 "hello"
converted_value = not_a_number.to_i # converted_value 变成了 0
puts "转换后的值为:#{converted_value}" # 输出:转换后的值为:0

to_i 遇到一个不以有效数字开头的字符串(比如 "hello""abc123")时,它会将该字符串转换为 0。如果字符串以数字开头,但后面跟着非数字字符(比如 "123abc"),它只会转换开头的数字部分(因此 "123abc".to_i 结果是 123)。了解这种行为非常重要,因为 0 可能本身就是一个有效的年龄或数量,这有可能会掩盖用户的无效输入错误。

2.2 使用 to_f 转换为浮点数

同样,如果你预期用户输入的是带有小数点的数字(浮点数),你可以使用 to_f 方法。

puts "请输入你的身高(单位:米,例如 1.75):"
height_as_string = gets.chomp
# 如果用户输入 "1.75",height_as_string 就是 "1.75"(一个字符串)。
height_as_float = height_as_string.to_f
# height_as_float 现在是 1.75(一个浮点数)。
puts "你的身高是 #{height_as_float} 米。"
puts "你身高的两倍是 #{height_as_float * 2} 米。"
# 正确执行了浮点数运算。

# 类似于 to_i,`to_f` 也会处理非数字输入:
puts "请输入一个小数:"
invalid_float_input = gets.chomp # 用户输入了 "twenty-five"
converted_float = invalid_float_input.to_f # converted_float 变成了 0.0
puts "转换后的浮点数为:#{converted_float}" # 输出:转换后的浮点数为:0.0

就像 to_i 一样,to_f 会将非数字字符串转换为 0.0。如果字符串包含数字和其他字符的混合,它也只会解析开头的数字部分(例如,"3.14pi".to_f 会变成 3.14)。

3. 提示用户输入

为了提供良好的用户体验,必须明确告诉用户你的程序期望得到什么样的输入。这是通过在调用 gets 之前向用户显示提示词 (Prompt) 来实现的。Ruby 提供了两种主要的输出方法:putsprint

3.1 使用 puts 进行提示

puts("put string" 的缩写)会显示你提供的字符串,并在末尾追加一个换行符。这意味着在提示词显示后,光标会移动到下一行。

# 使用 puts 进行提示
puts "请输入你的名字:"
first_name = gets.chomp # 用户将在下一行输入内容
puts "你好,#{first_name}!"

在这种情况下,用户会在提示词的下方一行输入内容,这会让交互界面显得比较空旷。

3.2 使用 print 进行提示

print 也会显示你提供的字符串,但它不会在末尾添加换行符。这意味着提示词显示后,光标会停留在同一行,允许用户紧挨着提示词后面输入内容。

# 使用 print 进行提示
print "请输入你的姓氏: " # 注意提示词末尾留了一个空格
last_name = gets.chomp # 用户将在与提示词同一行的位置输入内容
puts "你的姓氏是 #{last_name}。"

在命令行应用程序中,使用 print 通常能创造出更自然的对话流,因为用户的回答直接紧挨着问题出现。一个常见的标准做法是在 print 提示字符串的末尾加上一个空格,以便在视觉上将提示词与用户的输入隔开。

4. 处理多个输入

大多数交互式程序需要从用户那里获取不止一项信息。你可以根据需要,简单地重复“提示 -> 获取输入 -> 转换数据类型”的模式。

让我们创建一个收集个人信息的简单程序:

# 收集用户信息的程序

# 1. 询问名字
print "请输入你的名字: "
first_name = gets.chomp

# 2. 询问姓氏
print "请输入你的姓氏: "
last_name = gets.chomp

# 3. 询问年龄并转换为整数
print "请输入你的年龄: "
age = gets.chomp.to_i

# 4. 询问城市
print "请输入你居住的城市: "
city = gets.chomp

# 5. 询问最喜欢的数字并转换为浮点数(允许输入小数)
print "请输入你最喜欢的数字: "
favorite_number = gets.chomp.to_f

puts "\n--- 用户信息汇总 ---"
puts "姓名:#{first_name} #{last_name}"
puts "年龄:#{age} 岁"
puts "城市:#{city}"
puts "最喜欢的数字:#{favorite_number}"

# 使用其中一个数值输入进行简单的计算
puts "明年,你将是 #{age + 1} 岁。"

在这个例子中,我们按顺序提示用户输入不同的信息。每次输入都被存储在它自己的变量中。我们使用 gets.chomp 清理输入的字符串,并在预期需要数值输入时使用 to_ito_f。这展示了如何构建一个基础的交互式会话。

在处理用户输入时(尤其是数值输入),考虑“如果用户输入了预期外的数据(比如需要数字却输入了文本)该怎么办”是一个很好的编程习惯。虽然关于稳健的输入验证和错误处理的完整内容将在后面的章节(具体来说是“使用 begin...rescue 进行基本错误处理”)中讲解,但你可以利用条件语句(在第 3 模块:控制流 中学过)进行基础的检查。例如,你可以在 to_i 转换后检查 age 是否为 0,因为这可能暗示了一个无效的输入。