'undefined method '>' for nil:NilClass in ruby



这是我将用户输入的字符串转换为凯撒密码的代码。

puts "text?"
text = gets.chomp
puts "key?"
key = gets.chomp.to_i 
plainTex = Array.new 
ciphTex = Array.new
j = 0 
text.each_byte do |i|
plainTex[j] = i
j += 1
end
j = 0 
plainTex.each_entry do |i|
if ( i == 32 )
ciphTex[j] = plainTex[j]
j += 1
end
if( plainTex[j] > 64) and (plainTex[j] < 91 )
if( (plainTex[j] + key) > 91)
ciphTex[j] = (plainTex[j] + key ) - 90
j += 1
else 
ciphTex[j] = plainTex[j] + key 
j += 1 
end
end
if( plainTex[j] > 94) and (plainTex[j] < 123)
if( (plainTex [j] + key) > 122)
ciphTex [j] = (plainTex[j] + key) - 122
j += 1 
else 
ciphTex[j] = plainTex[j] + key
j += 1
end
end
end 
ciphTex.each_entry do |i|
puts i
end

现在,我出现错误:nil:NilClass(NoMethodError)的未定义方法">'

在网上搜索后,我得出结论,plainTex可能为零,正如错误消息所说(事实并非如此,因为plainTex是预先提供数据的)。

附带说明:当输入字符串

全部为小写且没有空格时,程序运行良好那么,我做错了什么?

问题说明

当您使用超出界限的索引访问数组时,不会得到任何错误,但结果是nil

irb --simple-prompt
>> a = [1]
=> [1]
>> a[0]
=> 1
>> a[1]
=> nil
>> a[200]
=> nil

调试代码

一点看跌期权声明揭示了问题:

text.each_byte do |i|
plainTex[j] = i
j += 1
end
j = 0 
puts "Length: #{plainTex.length}"
plainTex.each_entry do |i|
if ( i == 32 )
ciphTex[j] = plainTex[j]
j += 1
end
puts "j: #{j}"

这是输出

text?
Testing Test
key?
32
Length: 12
j: 0
j: 2
j: 3
j: 4
j: 5
j: 6
j: 7
j: 8
j: 10
j: 11
j: 12
test.rb:30:in `block in <main>': undefined method `>' for nil:NilClass (NoMethodError)
from test.rb:23:in `each'
from test.rb:23:in `each_entry'
from test.rb:23:in `<main>

在本例中,数组的最后一个索引是11,您访问了索引12。您得到了结果nil,然后尝试在nil上调用方法>

专业调试

您可以安装gempry-byebug,并使用短别名sn作为步骤进入、下一步等。

https://github.com/deivid-rodriguez/pry-byebug

发现Bug

使用pry-byebug可以立即清楚地了解错误是什么,尽管我并不真正理解你的代码,因为这些数字对我来说毫无意义

对于第一个字母,它在第二个条件if( plainTex[j] > 64) and (plainTex[j] < 91 )中递增j。然后随着j的递增,它移动到if( plainTex[j] > 94) and (plainTex[j] < 123),在那里它再次递增。

您应该对所有这些使用elsif或使用next

代码清理

Ruby惯例是使用snake大小写来命名变量,我会更改这段代码:

if( plainTex[j] > 64) and (plainTex[j] < 91 )
if( (plainTex[j] + key) > 91)
ciphTex[j] = (plainTex[j] + key ) - 90
j += 1
else 
ciphTex[j] = plainTex[j] + key 
j += 1 
end
end

到此:

if plain_text[j].between?(65, 90)
ciph_text[j] = plain_text[j] + key
ciph_text[j] -= 90 if ciph_text[j] > 91
j += 1
end

似乎您在每个条件下都重复j+=1,所以为什么不将其删除到if/else块之外,并将其作为循环end之前的最后一行呢?

我也是一个人,我不想记住";A";是65;Z";是90。为什么不在代码中这样说呢?

if plain_text[j].between?("A".ord, "Z".ord)

我从来没有在ruby中弄乱过ASCII,但我相信你可以进一步改进这一点,可能用10行或更少的代码在一个简单的循环中完成整个密码。

Ruby非常擅长处理数组,所以请使用它。我会这样做:

plain_text = text.codepoints
cyph_text = plain_text.map do |code|
if code == ' '.ord
' '.ord
elsif
# return cypher code
end
end

看看地图功能是如何工作的。

最新更新