您的translate 方法不起作用。问题出在这里:
if word[0] == "a" || "e" || "o" || "u" || "i"
和
elsif word[0] != "a" || "e" || "o" || "u" || "i"
你不能这样比较,因为任何一方的右边都不会像你想象的那样。
一些简单的检查会显示出问题的原因:
'abc'[0] == "a" || "e" || "o" || "u" || "i" # => true
'efg'[0] == "a" || "e" || "o" || "u" || "i" # => "e"
'opq'[0] == "a" || "e" || "o" || "u" || "i" # => "e"
'xyz'[0] == "a" || "e" || "o" || "u" || "i" # => "e"
'abc'[0] != "a" || "e" || "o" || "u" || "i" # => "e"
'efg'[0] != "a" || "e" || "o" || "u" || "i" # => true
'opq'[0] != "a" || "e" || "o" || "u" || "i" # => true
'xyz'[0] != "a" || "e" || "o" || "u" || "i" # => true
为什么错了?让我们看看发生了什么:
当单词以'a'开头时,测试'a' == 'a'为真:
'abc'[0] == "a" # => true
如果我们||(“或”)为真,我们会返回真,因为这是第一个看到的“真”值:
true || "e" # => true
如果第一个测试失败,那么 || 会导致对第二个测试进行评估,在您的代码中是 "e",并且不是测试,但 Ruby 不知道这一点,并认为这是"true" 返回值所以它变成了表达式的结果:
false || "e" # => "e"
知道,正确的写法是:
'abc'[0] == "a" || 'abc'[0] == "e" || 'abc'[0] == "o" || 'abc'[0] == "u" || 'abc'[0] == "i" # => true
'efg'[0] == "a" || 'efg'[0] == "e" || 'efg'[0] == "o" || 'efg'[0] == "u" || 'efg'[0] == "i" # => true
'opq'[0] == "a" || 'opq'[0] == "e" || 'opq'[0] == "o" || 'opq'[0] == "u" || 'opq'[0] == "i" # => true
'xyz'[0] == "a" || 'xyz'[0] == "e" || 'xyz'[0] == "o" || 'xyz'[0] == "u" || 'xyz'[0] == "i" # => false
'abc'[0] != "a" && 'abc'[0] != "e" && 'abc'[0] != "o" && 'abc'[0] != "u" && 'abc'[0] != "i" # => false
'efg'[0] != "a" && 'efg'[0] != "e" && 'efg'[0] != "o" && 'efg'[0] != "u" && 'efg'[0] != "i" # => false
'opq'[0] != "a" && 'opq'[0] != "e" && 'opq'[0] != "o" && 'opq'[0] != "u" && 'opq'[0] != "i" # => false
'xyz'[0] != "a" && 'xyz'[0] != "e" && 'xyz'[0] != "o" && 'xyz'[0] != "u" && 'xyz'[0] != "i" # => true
然而,这很快变得难以阅读和笨拙,所以需要更简洁的东西:
%w[a e o u].include? 'abc'[0] # => true
%w[a e o u].include? 'efg'[0] # => true
%w[a e o u].include? 'opq'[0] # => true
%w[a e o u].include? 'xyz'[0] # => false
!%w[a e o u].include? 'abc'[0] # => false
!%w[a e o u].include? 'efg'[0] # => false
!%w[a e o u].include? 'opq'[0] # => false
!%w[a e o u].include? 'xyz'[0] # => true
这有一个问题;随着数组大小的增加,需要更多循环来与[0] 值进行比较,这会不必要地减慢代码速度。正确编写的正则表达式可以摆脱这种循环,因此速度保持非常恒定:
'abc'[0][/[aeou]/] # => "a"
'efg'[0][/[aeou]/] # => "e"
'opq'[0][/[aeou]/] # => "o"
'xyz'[0][/[aeou]/] # => nil
但请注意,结果不是真/假,而是与模式匹配的字符或 nil。在 Ruby 中,只有 nil 和 false 被认为是 false 值,其他一切都是 true,因此我们可以将它们分别转换为 true、true、true、false,但是通过利用 ! 运算符,我们可以使其更加清晰:
!!'abc'[0][/[aeou]/] # => true
!!'efg'[0][/[aeou]/] # => true
!!'opq'[0][/[aeou]/] # => true
!!'xyz'[0][/[aeou]/] # => false
看起来我们必须使用!!! 来“不”获得使用!= 时想要的结果,但这不是必需的。单个! 会做同样的事情:
!'abc'[0][/[aeou]/] # => false
!'efg'[0][/[aeou]/] # => false
!'opq'[0][/[aeou]/] # => false
!'xyz'[0][/[aeou]/] # => true
但是等等!还有更多!通过删除字符串切片 ([0]) 并使用正则表达式锚点,即使这一点也可以稍微改善。比较这两者及其基准:
require 'fruity'
ALPHABET = ('a'..'z').to_a.join
compare do
slice_it { ALPHABET[0][/[aeou]/] }
regex_it { ALPHABET[/^[aeou]/] }
end
# >> Running each test 8192 times. Test will take about 1 second.
# >> regex_it is faster than slice_it by 39.99999999999999% ± 10.0%
所以,使用类似的东西:
'abc'[/^[aeou]/] # => "a"
!'abc'[/^[aeou]/] # => false
!!'abc'[/^[aeou]/] # => true
将快速而紧凑,让您测试以查看字符串以什么开头。