[英]private method called noMethodError ruby
I've been trying to work the following problem out and ran into the error. 我一直在尝试解决以下问题并遇到错误。 The point of the problem is to use a given key sequence to encrypt a string. 问题的关键是使用给定的密钥序列来加密字符串。 For example, when given "cat" and [1,2,3] the result should be "dcw" Any suggestions? 例如,当给定“ cat”和[1,2,3]时,结果应为“ dcw”。有什么建议吗? the error was the following 错误是以下
def vigenere_cipher(string, key_sequence)
keyIndex=0
string=string.each_char.map do |c|
c=c.shift!(c,keyIndex)
keyIndex+=1
if keyIndex=key_sequence.length
keyIndex=0
end
end
return string
end
def shift!(c,keyIndex)
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
inititalLetterIndex=alphabet.index(c)
finalLetterIndex=alphabet[inititalLetterIndex+keyIndex]
return alphabet[finalLetterIndex]
end
vigenere_cipher("cat", [1,2,3])
# private method `shift!' called for "c":String (NoMethodError)
You are trying to call shift!
您正在尝试打电话给shift!
on string object that does not define on String
Class, instead you defined on main object. 在未在String
类上定义的字符串对象上,而是在主对象上定义。 You can call it like shift!(c,keyIndex)
instead of c.shift!(c,keyIndex)
您可以像shift!(c,keyIndex)
那样调用它shift!(c,keyIndex)
而不是c.shift!(c,keyIndex)
If you want to call you method shift!
如果您想调用方法shift!
on a string, you will have to define it on String
class. 在字符串上,您将必须在String
类上对其进行定义。
class String
def shift!(keyIndex)
# you can access `c` using `self` here
...
end
end
Then you can call it as c.shift!(keyIndex)
(Note the arguments are different). 然后,您可以将其称为c.shift!(keyIndex)
(注意参数是不同的)。
cipher.rb:4:in `block in vigenere_cipher': private method `shift!' called for "c":String (NoMethodError)
shift!
isn't defined in String class, but at the top level. 不是在String类中定义的,而是在顶层定义的。 So replace c=c.shift!(c,keyIndex)
by c=shift!(c,keyIndex)
因此,将c=c.shift!(c,keyIndex)
替换为c=shift!(c,keyIndex)
cipher.rb:17:in `[]': no implicit conversion of String into Integer (TypeError)
Line 16 defines : 第16行定义:
finalLetterIndex=alphabet[inititalLetterIndex+keyIndex]
alphabet contains letters as Strings, so finalLetterIndex
isn't an index (Numeric), but a String. 字母包含作为字符串的字母,因此finalLetterIndex
不是索引(数字),而是字符串。
On line 17, you try to use this String as an index. 在第17行,您尝试使用此String作为索引。
Replace line 16 with : 将第16行替换为:
finalLetterIndex=inititalLetterIndex+keyIndex
Your script doesn't raise any exception anymore. 您的脚本不再引发任何异常。 It also doesn't display anything, so add a puts to the last line : 它也不显示任何内容,因此在最后一行添加一个puts:
puts vigenere_cipher("cat", [1,2,3]).inspect
It returns : 它返回:
[0, 0, 0]
keyIndex
seems to be stuck at 0. Why? keyIndex
似乎停留在0。为什么? Look at line 6 : 看第6行:
if keyIndex=key_sequence.length
It doesn't test an equality, it assigns keyIndex
to key_sequence.length
. 它不测试相等性,而是将keyIndex
分配给key_sequence.length
。 Since any number is truthy in Ruby, it executes the code inside the if statement. 由于任何数字在Ruby中都是真实的,因此它将在if语句中执行代码。 Replace with 用。。。来代替
if keyIndex==key_sequence.length
Your code returns [nil, nil, 0]
. 您的代码返回[nil, nil, 0]
。 Why? 为什么?
string
is defined as the result of map
. string
定义为map
的结果。 map
returns an Array, in which each element is the result of the last executed command inside the block : in this case, the if
statement. map
返回一个Array,其中每个元素都是该块内最后执行的命令的结果:在本例中为if
语句。
if
returns nil
when the condition isn't satisfied, and returns the last executed command otherwise. if
不满足条件, if
返回nil
,否则返回最后执行的命令。 In this case 0
. 在这种情况下为0
。
Add c
at the last line of your map
block. 添加c
在你的最后一行map
块。
Your code now returns ["c", "b", "v"]
. 您的代码现在返回["c", "b", "v"]
。 Why? 为什么?
You only shift by shiftIndex
, not by the amount defined in key_sequence
Array. 您只能移动shiftIndex
,而不移动key_sequence
Array中定义的数量。 Replace 更换
c=shift!(c,keyIndex)
with 与
c=shift!(c,key_sequence[keyIndex])
Your code returns ["d", "c", "w"]
. 您的代码返回["d", "c", "w"]
。 Almost there! 快好了!
Ruby is a dynamic language. Ruby是一种动态语言。 You're free to overwrite the String string
with an Array, but it will confuse others and your future self. 您可以随意使用Array覆盖String string
,但这会混淆其他人和您未来的自我。
Use array
or letters
instead of string
, and return letters.join
使用array
或letters
代替string
,并返回letters.join
Your script now returns "dcw"
. 您的脚本现在返回"dcw"
。
It should look like : 它应该看起来像:
def vigenere_cipher(string, key_sequence)
keyIndex=0
letters=string.each_char.map do |c|
c=shift!(c,key_sequence[keyIndex])
keyIndex+=1
if keyIndex==key_sequence.length
keyIndex=0
end
c
end
return letters.join
end
def shift!(c,keyIndex)
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
inititalLetterIndex=alphabet.index(c)
finalLetterIndex=inititalLetterIndex+keyIndex
return alphabet[finalLetterIndex]
end
vigenere_cipher("Hello", [1,2,3])
raises 加薪
cipher.rb:17:in 'shift!': undefined method '+' for nil:NilClass (NoMethodError)
. cipher.rb:17:in 'shift!': undefined method '+' for nil:NilClass (NoMethodError)
。
Well, 'H' isn't found in your alphabet. 好吧,在您的字母中找不到'H'。 Use downcase : 使用小写:
array=string.downcase.each_char.map do |c|
vigenere_cipher("Hello World", [1,2,3])
doesn't work either, because of the space. 由于空间原因,也不起作用。 Delete anything that isn't a letter : 删除所有不是字母的内容:
array=string.downcase.delete('^a-z').each_char.map do |c|
vigenere_cipher("zzz", [1,2,3])
returns an empty String, because there's no letter after z
. 返回一个空字符串,因为z
后面没有字母。
Use modulo 26 : 使用模26:
return alphabet[finalLetterIndex%26]
Remove typos, don't use camelCase for variables, remove unnecessary return
and you get : 删除错别字,不要使用camelCase作为变量,删除不必要的return
,您会得到:
def vigenere_cipher(string, key_sequence)
key_index = 0
letters = string.downcase.delete('^a-z').each_char.map do |c|
c = shift(c, key_sequence[key_index])
key_index = (key_index + 1) % key_sequence.length
c
end
letters.join
end
def shift(c, key_index)
alphabet = ('a'..'z').to_a
initial_letter_index = alphabet.index(c)
final_letter_index = initial_letter_index + key_index
alphabet[final_letter_index % 26]
end
Using each_char
, zip
and cycle
, I'd rewrite the whole code this way : 使用each_char
, zip
和cycle
,我可以这样重写整个代码:
class Integer
# 0 => 'a', 1 => 'b', ..., 25 => 'z', 26 => 'a'
def to_letter
('a'.ord + self % 26).chr
end
end
class String
# 'A' => '0', 'a' => 0, ..., 'z' => 25
def to_code
self.downcase.ord - 'a'.ord
end
end
def vigenere_cipher(string, key)
short_string = string.delete('^A-Za-z')
short_string.each_char.zip(key.cycle).map do |char, shift|
(char.to_code + shift).to_letter
end.join
end
Wikipedia article uses a String as key : Wikipedia 文章使用String作为键:
def vigenere_cipher(string, key)
short_string = string.delete('^A-Za-z')
short_string.each_char.zip(key.each_char.cycle).map do |char, shift|
(char.to_code + shift.to_code).to_letter
end.join
end
vigenere_cipher('Attack at dawn!', 'LEMON').upcase # => "LXFOPVEFRNHR"
You should also be able to decrypt the message : 您还应该能够解密消息:
def vigenere_cipher(string, key, decrypt = false)
short_string = string.delete('^A-Za-z')
short_string.each_char.zip(key.each_char.cycle).map do |char, shift|
(char.to_code + shift.to_code * (decrypt ? -1 : 1)).to_letter
end.join
end
vigenere_cipher("LXFOPVEFRNHR", 'LEMON', :decrypt) #=> "attackatdawn"
Well, that was longer than expected! 好吧,那比预期的要长! :D :D
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.