我目前正在学习Ruby,并尝试过Simple Cipher挑战。我现在正在研究以下解决方案,并试图进行反向工程以了解该解决方案背后的思考过程。以下是该解决方案的链接。我将详细介绍我对每个代码段的理解。如果它们不正确,您能纠正我吗?谢谢!https://exercism.io/tracks/ruby/exercises/simple-cipher/solutions/b200c3d9f10e497bbe2ca0d826df2661
class Cipher
ALPHABET = [*'a'..'z']
attr_reader :key
def initialize(key = nil)
@key = key || 100.times.map { ALPHABET.sample }.join
fail ArgumentError, 'invalid chars in key' unless valid?(@key)
end
def encode(text)
a = 'a'.ord
text.chars.zip(@key.chars).map do |char, key|
ALPHABET[(char.ord - a + key.ord - a) % ALPHABET.length]
end.join
end
def decode(code)
code.chars.zip(@key.chars).map do |char, key|
ALPHABET[char.ord - key.ord]
end.join
end
private
def valid?(key)
!key.empty? && key !~ /[^a-z]/
end
end
第1部分
@@ =密钥是否匹配密钥。ALPHABET被随机化(使用.sample方法)并加入。然后将随机连接的字母迭代100次,并返回一个新数组(使用map方法)。
要处理无效的键错误,请使用fail ArgumentError。
def initialize(key = nil)
@key = key || 100.times.map { ALPHABET.sample }.join
fail ArgumentError, 'invalid chars in key' unless valid?(@key)
end
第2部分我了解此代码的目的是将纯文本转换为加密文本。但是,我在下面的代码中苦苦挣扎。
def encode(text)
a = 'a'.ord
text.chars.zip(@key.chars).map do |char, key|
ALPHABET[(char.ord - a + key.ord - a) % ALPHABET.length]
end.join
end
内部。map方法块,有两个参数:char和key。 char表示原始纯文本中的字符,而key表示加密的密钥字符。
我在理解此ALPHABET[(char.ord - a + key.ord - a) % ALPHABET.length]
部分时遇到麻烦。使用.ord方法将ALPHABET原始纯文本和加密密钥文本字符转换为ASCII值。为什么从这些值中减去一个值?为什么要使用%运算符和ALPHABET.length?
第3部分在这一部分中,使用解码方法,代码。代码是两方(发送者和接收者)之间共享的秘密密钥。但是为什么ALPHABET[char.ord - key.ord]
?字符ascii-密钥ascii值将提供解密的纯文本。我不知道它是如何工作的?
def decode(code)
code.chars.zip(@key.chars).map do |char, key|
ALPHABET[char.ord - key.ord]
end.join
end
第4部分private方法用于将这段代码与其他类分开。有效的方法是验证密钥。有两个条件:键不能为空或必须为小写字母。
private
def valid?(key)
!key.empty? && key !~ /[^a-z]/
end
@@ =密钥是否匹配密钥。 ALPHABET被随机化(使用.sample方法)并加入。然后将随机连接的字母迭代100次,并返回一个新数组(使用map方法)。
@key = key
,如果key
不为假(nil
或false
);否则,迭代100
次并从ALPHABET
中收集一个随机字符;然后将所得的100个元素的数组连接到字符串中,并将string分配给@key
。什么都没有返回。
ord方法-将字符转换为其ASCII值。
a = 'a'.ord
。为什么选择此字符?不是z或其他字符?
因为"a"
以Unicode(也为ASCII,但在这种情况下,.ord
以Unicode操作)开始以ASCII字母顺序,其值为97
。但是我们对字符在字母表中而不是在Unicode中的位置感兴趣。这样想:现在是20:37,您正在听歌剧。演奏从19:00
开始。你听了多久了?您减去20:37 - 19:00
,得到答案(1小时37分钟)。同样,要知道'c'
是#2字符(英语中我们会说第3个字符,但是Ruby从0开始计数,因此'a'
是#0,'c'
是#2),则减去位置从'a'
的位置开始'c'
的位置:99 - 97
。您不会从23:00
中减去20:37
或其他任何时间,因为这对于找出您收听了多长时间没有任何意义;使用'a'.ord
而不是'z'
或其他字符的相同原因。
。zip方法-此方法用于比较原始纯文本字符和加密字符。
[不,它只是通过将text.chars
中的每个元素与@key.chars
中的对应元素配对来创建一个新数组。没有比较正在进行。
我在理解此ALPHABET [(char.ord-a + key.ord-a)%ALPHABET.length]部分时遇到麻烦。使用.ord方法将ALPHABET原始纯文本和加密密钥文本字符转换为ASCII值。为什么从这些值中减去一个值?为什么使用%运算符和ALPHABET.length?
请参见上文有关a
的原因。
此密码通过将每个字符偏移与键中相应字符的字母位置相对应的空格数来工作。 %
将包装所有内容,以便结果始终是ALPHABET
的有效索引。例如,如果char.ord - a + key.ord - a
恰好超过ALPHABET
的长度,则它将环绕到起点。例如,如果您在上述计算中获得29
,由于没有字母#29,因此通常会获得nil
的ALPHABET[29]
。但29 % 26
为3
,并且ALPHABET[3]
有效。
第3部分,在此部分中,使用解码方法,代码。代码是两方(发送者和接收者)之间共享的秘密密钥。但是为什么要使用ALPHABET [char.ord-key.ord]?字符ascii-密钥ascii值将提供解密的纯文本。我不知道它是如何工作的?
已转移的内容无法转移;这就是解码的样子。在我们将两个字符(char.ord - a) + (key.ord - a)
的位置相加之前,现在我们将它们相减:(char.ord - a) - (key.ord - a)
。进行一些数学运算,您将看到两个a
在该减法中将互相抵消,因此(char.ord - a) - (key.ord - a)
等效于char.ord - key.ord
。
[之前,我们担心添加的内容可能超出字母的大小。在这里,人们可能会担心减法会变成负数。但是Ruby现在有了我们的支持:Ruby中的ALPHABET[-3]
表示“末尾的第三个元素”,因此等效于ALPHABET[23]
;不需要%
。