题目为栅栏密码的W变种,原理如下
W变种
1 2 3 4 5 6 7 8 9 0 # key=3 Rail-fence Cipher
1 .. .. .. 5 .. .. .. 9 .. ↘ ↗ ↗
.. 2 .. 4 .. 6 .. 8 .. 0 ↘ ↗ ↘ ↗ ↘
.. .. 3 .. .. .. 7 .. .. .. ↘ ↘
结果为 1 5 9 2 4 6 8 0 3 7
代码
码是自己边想边写的,调bug调了整一天... 应该是没有什么致命的bug了,至少解题是没问题的。
思路主要是以如“1234”“5678”这样的V字为循环体,先按行拆解成列表形式,再进行拼接。
比较关键的点是根据最后一个可能不完整的“V”,如“90”,进行分类讨论。
大概不是最优的解法吧... 有dalao路过的话,看看有没有什么更好的思路吧。
# D:\Work\code_of_python3.9.7\栅栏密码_W.py
# 解密函数,形参为密文和秘钥(可重复尝试秘钥进行爆破)
def Railfence_W_Decode(str, key):
# 解密关键思路:
# 密文中的每个“V”的字节长度为2key-2
tmp = ''
# 先算出一些关键的数据
len_of_v = 2 * key - 2
len_of_str = len(str)
num_of_v = len_of_str // len_of_v # 密文一共包含了几个完整的V,也就是第一行的长度(除了最后一个v)
len_of_last_v = len_of_str % len_of_v # 最后一个V的长度
# 先把每一行抽出来
list = [''] * key
# 第一行
if len_of_last_v > 0: # 判断一下最后一个不完整的“V”到底存不存在
len_of_hang_i = num_of_v + 1
list[0] = str[0:len_of_hang_i]
else:
len_of_hang_i = num_of_v
list[0] = str[0:len_of_hang_i]
# 第二行到第n-1行
if len_of_last_v <= key: # 分类讨论:最后一个“V”有没有反折,会影响中间第二至第n-1行的长度
for i in range(1, key - 1):
if i < len_of_last_v:
# 在最后一个“V”不反折的情况下,受到影响的几行要从密文中多拿1位
len_of_hang_i1 = 2 * num_of_v + 1
else:
len_of_hang_i1 = 2 * num_of_v
list[i] = str[len_of_hang_i:len_of_hang_i + len_of_hang_i1] # 扣出第i行字符串
len_of_hang_i += len_of_hang_i1 # 把下标放到下一次循环的开始
else:
for i in range(1, key - 1):
if len_of_v - i < len_of_last_v:
# 在最后一个“V”反折的情况下,受到一次影响的几行要从密文中多拿1位,受到两次影响的要多拿2位
len_of_hang_i1 = 2 * num_of_v + 2
else:
len_of_hang_i1 = 2 * num_of_v + 1
list[i] = str[len_of_hang_i:len_of_hang_i + len_of_hang_i1] # 同上
len_of_hang_i += len_of_hang_i1 # 同上
# 第n行
list[key - 1] = str[len_of_hang_i:]
# 正式开始解密,把得出的V一个一个拼上去
# 忽略最后一个“V”的越界问题,用try解决
for i in range(num_of_v + 1):
try:
tmp += list[0][i]
except IndexError:
pass
for l in range(1, key - 1):
try:
tmp += list[l][2 * i]
except IndexError:
pass
try:
tmp += list[key-1][i]
except IndexError:
pass
for l in range(1, key - 1):
try:
tmp += list[key - 1 - l][2 * i + 1]
except IndexError:
pass
return tmp
# 加密函数,形参为密文和秘钥(可重复尝试秘钥进行爆破)
def Railfence_W_Encode(str, key):
tmp = ''
list = [''] * key
len_of_v = 2 * key - 2 # 老样子,计算一个“V”的长度
# 拆分为list:双指针取数,第一个指针确定区第几行,第二个指针在每一行进行移动取数
# 第一行
index = 0
while index < len(str):
list[0] += str[index]
index += len_of_v
# 第二行到第n-1行
for i in range(1, key - 1):
index = i
while index < len(str):
list[i] += str[index]
index_2 = (index - i) + (len_of_v - i)
if index_2 < len(str):
# 防止在最后一个“V”越界
list[i] += str[index_2]
index += len_of_v
# 最后一行
index = key - 1
while index < len(str):
list[key - 1] += str[index]
index += len_of_v
# list再拼接成tmp
for i in range(key):
tmp += list[i]
return tmp
# 下面是自由调整部分
# 解密
# str_code = '1592468037'
# key_code = 3
str_code = r'ccehgyaefnpeoobe{lcirg}epriec_ora_g'
key_code = 5
tmp_decode = Railfence_W_Decode(str_code, key_code)
print(tmp_decode)
# 爆破
# for i in range(2, len(str_code) + 1):
# tmp_decode = Railfence_W_Decode(str_code, i)
# print(tmp_decode)
# 加密
str = r'cyberpeace{railfence_cipher_gogogo}'
key = 5
# str = '1234567890'
# key = 3
tmp_encode = Railfence_W_Encode(str, key)
print(tmp_encode)
# 爆破(虽然加密并不怎么需要爆破)
# for i in range(2, len(str) + 1):
# tmp_encode = Railfence_W_Encode(str, i)
# print(tmp_encode)