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

