The method below should take an "encrypted" string and return the string "unencrypted", but it is returning the error "undefined method `-' for nil (NoMethodError)" I've tried everything but I can't get beyond that. basically the code is this:
ALPHABET = ('a'..'z').to_a
def decode(string, factor)
string = string.split(//)
string = string.each_with_index.map do |char, _|
if char.match(/\w/).nil?
char
else
ALPHABET[ALPHABET.index(char) - factor]
end
end
string.join
end
undefined method `-' for nil:NilClass
How can I solve this?
CodePudding user response:
You are setting your ALPHABET
only with lower case letters (ALPHABET = ('a'..'z').to_a
), but in the string, you are using some upper case letters ('Z', 'V'). As these letters won't be on the ALPHABET, the index related to them does not exist and will be nil
(e.g ALPHABET.index('Z')
is nil
).
In order to solve that, considering that the letters case on the output is not relevant, you can just do a preprocessing on your string converting all the letters to lower case, and you will then get the expected result:
ALPHABET = ('a'..'z').to_a
def decode(string, factor)
string = string.downcase.split(//) # converting into downcase here
string = string.each_with_index.map do |char, _|
if char.match(/\w/).nil?
char
else
ALPHABET[ALPHABET.index(char) - factor]
end
end
string.join
end
string = "'Zd tytxtrzd cpnflclx op Vlcwdcfsp, xld lelnlclx l ntolop gtktysl!'"
factor = 11
puts decode(string, factor)
# => 'os inimigos recuaram de karlsruhe, mas atacaram a cidade vizinha!'
UPDATE considering that the case is relevant:
In this case, you can then define two alphabets (one for lower case and one for upper case), and then use them accordingly. Like this:
LOWCASE_ALPHABET = ('a'..'z').to_a
UPCASE_ALPHABET = ('A'..'Z').to_a
def decode(string, factor)
string = string.split(//) # converting into downcase here
string = string.each_with_index.map do |char, _|
if char.match(/\w/).nil?
char
else
# if is a lower case letter, uses lowcase alphabet and, otherwise, uses upcase alphabet
alphabet = /[a-z]/.match(char) ? LOWCASE_ALPHABET : UPCASE_ALPHABET
alphabet[alphabet.index(char) - factor]
end
end
string.join
end
string = "'Zd tytxtrzd cpnflclx op Vlcwdcfsp, xld lelnlclx l ntolop gtktysl!'"
factor = 11
puts decode(string, factor)
# => 'Os inimigos recuaram de Karlsruhe, mas atacaram a cidade vizinha!'
CodePudding user response:
Another version with one alphabet:
ALPHABET = ('a'..'z').to_a
def decode(string, factor)
string.each_char.map do |char|
index = ALPHABET.index(char.downcase)
decoded = index.nil? ? char : ALPHABET[index - factor]
char == char.downcase ? decoded : decoded.upcase
end.join
end
Priority of the code is readability/brevity over speed.