首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ruby中简单的凯撒密码分析

Ruby中简单的凯撒密码分析
EN

Code Review用户
提问于 2016-02-26 03:17:37
回答 1查看 250关注 0票数 3

我真的很喜欢Ruby,我想做得更好。如有任何意见,我们将不胜感激。

描述

该程序提示用户输入一个字符串,该字符串是凯撒密码给定(英文)明文和范围0,25上的密钥所产生的密文。然后,该程序使用英文字符频率表执行简单的密码分析,以确定前5种最可能的移位密钥,并在这些密钥用于解密密文时显示所产生的明文。

还应该指出的是,唯一需要输入的是字母和空格,但我认为它适用于大多数标点符号。

代码:

代码语言:javascript
复制
class Cryptanalysis
  def initialize
    @alphabet = ('A'..'Z').to_a.join

    @english_frequency = { :A => 0.080, :B => 0.015, :C => 0.030,
                           :D => 0.040, :E => 0.130, :F => 0.020,
                           :G => 0.015, :H => 0.060, :I => 0.065,
                           :J => 0.005, :K => 0.005, :L => 0.035,
                           :M => 0.030, :N => 0.070, :O => 0.080,
                           :P => 0.020, :Q => 0.002, :R => 0.065,
                           :S => 0.060, :T => 0.090, :U => 0.030,
                           :V => 0.010, :W => 0.015, :X => 0.005,
                           :Y => 0.020, :Z => 0.002 }
  end

  def decrypt_caesar(ciphertext, shift)
    i = shift % @alphabet.size
    decrypt = @alphabet
    encrypt = @alphabet[i..-1] + @alphabet[0...i]

    ciphertext.tr(encrypt, decrypt)
  end

  def analyze(ciphertext)
    chars = ciphertext.gsub(/[^A-Z]/i, '').split(//)
    ciphertext_frequency = character_frequency(chars)

    correlation_of_frequency = Hash.new

    alphabet = @alphabet.split(//)
    (0..25).each { |i|
      sum = 0.0
      alphabet.each { |c|
        e = alphabet.index(c)
        sum += ciphertext_frequency[c.to_sym] * @english_frequency[alphabet[(26 + e - i) % 26].to_sym]
      }
      correlation_of_frequency[i] = sum
    }

    correlation_of_frequency.sort_by { |_, v| -v }.take(5).to_h
  end

  def character_frequency(chars)
    frequency = Hash.new
    inc = 1.0 / chars.size

    @alphabet.each_char { |c| frequency[c.to_sym] = 0.0  }
    chars.each          { |c| frequency[c.to_sym] += inc }

    frequency
  end
end

crypt = Cryptanalysis.new

puts 'Enter a string to analyze'
text = gets.chomp.upcase
result = crypt.analyze(text)

puts 'Top 5 possible shifts: '
choice = 1

result.each do |k, v|
  puts '%10s) Shift amount: %2s Correlation: %%%.4f Result: %s' % [choice, k, v, crypt.decrypt_caesar(text, k)]
  choice += 1
end
EN

回答 1

Code Review用户

发布于 2016-02-27 06:34:11

干得好。您可以通过以下方法获得一些简单的改进:

  • 利用ruby的函数方法消除临时变量,使代码更具有声明性
  • 酌情使用常量
  • 通过在模块上而不是在类上使用静态方法来使代码反映您的风格--您实际上并没有将该类用于原始代码中的任何内容。或者,您可以在类构造函数中传入保存密文,然后执行类似于crypt_instance.analyze的操作。
  • 避免像25或26这样的“神奇数字”。

重写:

代码语言:javascript
复制
module Cryptanalysis
  ALPHABET = ('A'..'Z').to_a

  ENGLISH_FREQUENCY = { :A => 0.080, :B => 0.015, :C => 0.030,
                        :D => 0.040, :E => 0.130, :F => 0.020,
                        :G => 0.015, :H => 0.060, :I => 0.065,
                        :J => 0.005, :K => 0.005, :L => 0.035,
                        :M => 0.030, :N => 0.070, :O => 0.080,
                        :P => 0.020, :Q => 0.002, :R => 0.065,
                        :S => 0.060, :T => 0.090, :U => 0.030,
                        :V => 0.010, :W => 0.015, :X => 0.005,
                        :Y => 0.020, :Z => 0.002 }

  def self.decrypt_caesar(ciphertext, shift)
    decrypt = ALPHABET
    encrypt = ALPHABET.rotate(shift)
    ciphertext.tr(encrypt, decrypt)
  end

  def self.analyze(ciphertext)
    freqs = frequencies(clean(ciphertext))

    (0..ALPHABET.size)
    .map{|i| [i, score(freqs, i)]}
    .sort_by { |x| -x[1] }
    .take(5)
    .to_h
  end

  def self.clean(text)
    text.upcase.gsub(/[^A-Z]/i, '')
  end

  def self.score(freqs, shift)
    ENGLISH_FREQUENCY
    .values
    .rotate(shift)
    .zip(freqs.values)
    .map{|x| x.first * x.last}
    .reduce(:+)
  end

  def self.frequencies(text)
    ENGLISH_FREQUENCY
    .keys
    .map {|k| [k.to_sym, text.count(k.to_s) / text.size.to_f]}
    .to_h
  end
end

text = "the quick brown fox jumps over the lazy dog"
puts 'Top 5 possible shifts: ' 
puts Cryptanalysis.analyze(text)
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/121150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档