You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby实现替换密码加密时所有密文字符均为密钥末位I的bug排查

Ruby实现替换密码加密程序异常排查

问题基本信息

  • 加密密钥:VCHPRZGJNTLSKFBDQWAXEUYMOI
  • 待加密明文:Hello, CS-50!
  • 预期密文输出:Jrssb, HA-50!
  • 实际运行输出:Iiiii, II-50!
  • 已尝试操作:在每个匹配成功的if条件分支后添加break语句,问题未解决
  • 核心异常:所有密文的字母位均被替换为密钥的最后一位字符I

原实现代码

# Design and implement a program, substitution, that encrypts messages using a substitution cipher.
plaintext_str = 'Hello, CS-50!'
key_str = 'VCHPRZGJNTLSKFBDQWAXEUYMOI'

# Converting string into array:
plaintext = plaintext_str.split('')
key = key_str.split('')

# Check if letter is alphabetical
def alpha?(char)
  char.match?(/^[[:alpha:]]$/)
end

# Check if letter is in uppercase
def upper?(char)
  char.match?(/^[[:upper:]]$/)
end

# # Check if letter is in lowercase
def lower?(char)
  char.match?(/^[[:lower:]]$/)
end

# ASCII arrays value assigned to capital letters for alphabets
capital_letters = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
                   88, 89, 90]
# ASCII arrays value assigned to small letters for alphabets
small_letters = [97,
                 98,
                 99,
                 100,
                 101,
                 102,
                 103,
                 104,
                 105,
                 106,
                 107,
                 108,
                 109,
                 110,
                 111,
                 112,
                 113,
                 114,
                 115,
                 116,
                 117,
                 118,
                 119,
                 120,
                 121,
                 122]

# Define variable for ciphertext:
ciphertext = ''

# iterating each plaintext's char (i-th):
plaintext.each_index do |i|
  # iterating each key's char j-th on i-th char of plaintext:
  key.each_index do |j|
    # If char in plaintext is alphabetical:
    if alpha?(plaintext[i])
      # Check if letter is in uppercase
      if upper?(plaintext[i])
        capital_letters.each_index do |k|
          # Checking if plaintext's letter is equal to alphabet's letter in [j]
          if plaintext[i].ord == capital_letters[k]
            ciphertext[i] = key[j].upcase
            break
          end
        end
      # Check if letter is in lowercase
      elsif lower?(plaintext[i])
        small_letters.each_index do |l|
          if plaintext[i].ord == small_letters[l]
            ciphertext[i] = key[j].downcase
            break
          end
        end
      end
    # if non-alphabetical:
    else
      ciphertext[i] = plaintext[i]
    end
  end
end
puts "ciphertext: #{ciphertext}"

问题根因

  1. 循环逻辑完全错误:替换密码的映射规则是明文字母在字母表的序号直接对应密钥的下标,比如A/a对应密钥第0位,B/b对应密钥第1位,不需要遍历整个密钥数组。原代码对每个明文字符都套了一层遍历全部密钥下标的key.each_index循环,每遍历到一个密钥位就会覆盖一次ciphertext[i]的值。
  2. 添加的break没有生效:写的break只能跳出最内层遍历ASCII数组的k/l循环,根本不会终止外层遍历密钥的j循环,所以j会一直走到最后一位(下标25,对应字符I),之前写入的所有正确替换值都会被最后一次循环的I覆盖,最终所有字母位都输出I。
  3. 代码存在冗余:提前定义的capital_letters、small_lettersASCII数组完全没必要,直接通过字符编码差值就能算出字母在字母表的序号。

修复后代码

plaintext_str = 'Hello, CS-50!'
key_str = 'VCHPRZGJNTLSKFBDQWAXEUYMOI'
key = key_str.split('')
ciphertext = ''

def alpha?(char)
  char.match?(/^[[:alpha:]]$/)
end

def upper?(char)
  char.match?(/^[[:upper:]]$/)
end

plaintext_str.each_char do |c|
  if !alpha?(c)
    ciphertext << c
    next
  end
  # 计算当前字母在字母表的序号,A/a对应0,B/b对应1...
  char_index = upper?(c) ? c.ord - 'A'.ord : c.ord - 'a'.ord
  # 直接取对应下标的密钥字符,匹配原字符大小写
  cipher_char = upper?(c) ? key[char_index].upcase : key[char_index].downcase
  ciphertext << cipher_char
end

puts "ciphertext: #{ciphertext}"

运行后输出为ciphertext: Jrssb, HA-50!,和预期结果完全一致。


内容的提问来源于stack exchange,提问作者Yaroslav Yenkala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:57:21