xyh2695368537 发表于 2022-10-16 10:29:43

字符串作业 凯撒密码 字母偏移问题

16行代码,小甲鱼说%26取余是为了防止溢出是什么意思{:10_266:}

改成这样会出现什么问题吗
cipher.append(chr((ord(each) + key)))

tommyyu 发表于 2022-10-16 11:03:29

比如说z往后挪一位是a,但是他的ascii编码变成了123,不是a,此时就需要%26防止溢出

jackz007 发表于 2022-10-16 11:12:20

本帖最后由 jackz007 于 2022-10-16 14:49 编辑

      字母表有 26 个英文字母,如果给他们编上号,'A' 是 0,'B' 是 1,C 是 2,那么,'Z' 自然就是 25,很显然,根据这个编号就可以直接定位到字母,这个编号,就是通常所说的偏移。
chr(ord('A') + 0) = 'A'
chr(ord('A') + 1) = 'B'
chr(ord('A') + 25) = 'Z'
      很显然,如果偏移不在 0 ~ 25 以内,那么就会脱离字母表的范围,导致无法定位。
      凯撒密码的原理就是把每一个字母的偏移增加一个固定的数值,比如 4,从而,成为另外一个字母以达到加密的目的。既然偏移要加 4,那么,必然会有一部分字符在加密后的偏移数值会超出 0 ~ 25 的范围,从而导致无法定位字母,小甲鱼所说的"溢出",指的就是这个意思。
      那么,溢出怎么办呢?我们知道,取余操作有一个特性,如果被除数小于除数,那么,被除数就是余数,如果被除数大于等于除数,就用被除数减去除数,一直到被除数小于除数为止,新的被除数就是余数,所以,只要我们把新的偏移值对 26 取余,那么,偏移值不到 26 的时候,会维持原值,如果超出,就会自动减 26,直到小于26 为止.这样,就可以把字母表尾部的超出部分平移到字母表的开头,而这正是我们所预期的,于是,问题就圆满解决了。

def crypt(s , k):
    cipher = []
    for each in s:
      if 'A' <= each <= 'Z':
            cipher . append(chr(ord('A') + (ord(each) - ord('A') + k) % 26))
      elif 'a' <= each <= 'z':
            cipher . append(chr(ord('a') + (ord(each) - ord('a') + k) % 26))            
      else:
            cipher . append(each)
    return '' . join(cipher)

s , k = 'ABCDEFGH STUVWXYZ' , 4
s1 = crypt(s , k)       # 加密
print(s1)
s2 = crypt(s1 , -k)   # 解密
print(s2)

Brick_Porter 发表于 2022-10-16 11:13:19

https://ts1.cn.mm.bing.net/th/id/R-C.da310e141fa527e943947e338b128abe?rik=HOedOgelDOXBiQ&riu=http%3a%2f%2fapi.fly63.com%2fvue_blog%2fpublic%2fUploads%2f20181031%2f5bd931ecb8ae6.jpg&ehk=VlZdRqfFkhEsRpILTddMNu3jxOj8K1Ol47KYN4SGftI%3d&risl=&pid=ImgRaw&r=0
注意看这张ASCII对照表,尤其是字母Z后面的符号,不是小写字母a而是左中括号[。如果不%26那么就有可能英文字母(不论大写还是小写)加密之后不是字母而是其他符号。
假如明文是X,key是3,那么ord(each) - base + key = ord('X') - ord('A') + 3 = 88 - 65 + 3 = 26
查表可知26对应的是→,这显然不是我们希望的加密结果

xyh2695368537 发表于 2022-10-16 22:29:07

Brick_Porter 发表于 2022-10-16 11:13
注意看这张ASCII对照表,尤其是字母Z后面的符号,不是小写字母a而是左中括号[。如果不%26那么就有可能英 ...

清晰易懂,有图,有例子6666666
页: [1]
查看完整版本: 字符串作业 凯撒密码 字母偏移问题