简单密码-来自练习的Ruby

问题描述 投票:2回答:1

我目前正在学习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
  1. 。ord方法-将字符转换为其ASCII值。 a ='a'.ord。 为什么选择此字符?不是z或其他字符?
  2. 。chars方法-使用.chars方法将文本字符串分成每个单独的字符。 .chars比.split更有效率,因为它解析底层字节以返回字符串的字符(我在stackover流上阅读了.chars与.split的区别)。
  3. 。zip方法-此方法用于比较原始纯文本字符和加密字符。
  4. 。map方法-将该方法与一个块一起调用,并返回加密的文本。
  5. 内部。map方法块,有两个参数:char和key。 char表示原始纯文本中的字符,而key表示加密的密钥字符。

  6. 我在理解此ALPHABET[(char.ord - a + key.ord - a) % ALPHABET.length]部分时遇到麻烦。使用.ord方法将ALPHABET原始纯文本和加密密钥文本字符转换为ASCII值。为什么从这些值中减去一个值?为什么要使用%运算符和ALPHABET.length?

  7. 。join方法-我猜.join用于连接转换后的加密字符。我的理解正确吗?

第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
ruby string encryption caesar-cipher
1个回答
1
投票

@@ =密钥是否匹配密钥。 ALPHABET被随机化(使用.sample方法)并加入。然后将随机连接的字母迭代100次,并返回一个新数组(使用map方法)。

@key = key,如果key不为假(nilfalse);否则,迭代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,因此通常会获得nilALPHABET[29]。但29 % 263,并且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];不需要%

© www.soinside.com 2019 - 2024. All rights reserved.