0

我在试图弄清楚如何让我的解密功能工作时遇到了很多麻烦。它适用于味精可被 3 整除的理想情况,但在那之后我完全迷失了。我对我必须做什么有一个模糊的想法,因为我能够让它与两个导轨一起工作,但是三个导轨有更多的可能性。我很迷茫:(所有这些打印语句只是为了帮助我弄清楚我的程序中发生了什么。

import sys

def main():
    plaintext="abcdefgh"
    print(threeRailEncrypt(plaintext))
    print(threeRailDecrypt(threeRailEncrypt(plaintext)))


def threeRailEncrypt(plaintext):
    ciphertext=""
    rail1=""
    rail2=""
    rail3=""

    for i in range(len(plaintext)):
        if i%3 == 0:
            rail1=rail1+plaintext[i]
        elif i%3 == 1:
            rail2=rail2+plaintext[i]
        else:
            rail3=rail3+plaintext[i]

    ciphertext=rail1+rail2+rail3

    return(ciphertext)

def threeRailDecrypt(msg):
    if len(msg)%3==0:
        third=len(msg)//3
        print(third)
        rail1=msg[:third]
        rail2=msg[third:third*2]
        rail3=msg[third*2:]
        print(rail1,rail2,rail3)
        dm=""
        for i in range(third):
            dm=dm+rail1[i]
            dm=dm+rail2[i]
            dm=dm+rail3[i]
    else:
        third=(len(msg)//3)+1
        print(third)
        rail1=msg[:third]
        rail2=msg[third:third*2]
        rail3=msg[third*2:]
        print(rail1,rail2,rail3)
        dm=""
        for i in range(third):
            dm=dm+rail1[i]
            print(dm)
            dm=dm+rail2[i]
            print(dm)
            dm=dm+rail3[i]
            print(dm)
            if  len(rail2)>len(rail3):
                dm=dm+rail2[-1]
        return(dm)
main()

进步-

def threeRailDecrypt(cypher, rails = 3):
    length = len (cypher)
    for i in range(rails):
        lens=(length//rails)
        if length % rails > i:
            lens=lens+1
        print(lens)
4

3 回答 3

1

我将使用完全不同的方法和更明确的代码添加第二个答案:

def dec2 (cypher):
    length = len (cypher)
    if length < 4: return cypher
    third = length // 3 + (1 if length % 3 else 0)
    cypher = list (cypher)
    if length % 3 == 1: cypher.insert (third * 2 - 1, '')
    return ''.join (''.join (cypher [i::third] ) for i in range (third) )

或者只是震惊你的老师:

enc = lambda p:''.join(p[_::3]for _ in range(3))
dec = lambda c:c if len(c)<4 else(lambda *a:(lambda c,t:
''.join(''.join(c[i::t])for i in range(t)))((lambda c,t,
l:c[:t*2-1]+(['']if l%3==1 else[])+c[t*2-1:])(*a),a [2])
)(*(lambda c:(list(c),len(c),len(c)//3+(1 if len(c)%3
else 0)))(c))
于 2013-10-03T01:33:16.283 回答
1

您只需像在加密函数中所做的那样再次拆分字符串,然后遍历它们以将每个字符放回其真实位置。

def decrypt(crypt):
    rails = []
    result = ""
    rails.append(crypt[:(len(crypt)+2)/3])
    rails.append(crypt[(len(crypt)+2)/3:-(len(crypt)-2)/3])
    rails.append(crypt[-(len(crypt)/3):])
    for x in range(len(crypt)):
        result += rails[x%3][:1]
        rails[x%3] = rails[x%3][1:]
    return(result)

我认为 Hyperboreus 的第二种解决方案更酷!

OLD(与评论相关的有趣想法,但对于较长的字符串并没有按预期工作):

您只需要反转您在加密中所做的事情,因此在加密中您通过使用模 3 将它们拆分来打乱文本。再次获取明文的最简单方法是简单地运行加密方法字符串的长度减去加密字符串的两倍,它将恢复为纯文本。

def threeRailDecrypt(crypt):
    for i in range(len(crypt)-2):
        crypt = threeRailEncrypt(crypt)
    return(crypt)

Hyperboreus 解决方案是正确的解决方案,但我认为这更容易理解。

字符串测试示例:

测试 - 未受影响

ttes - 第一次迭代(加密)

tste - 第二次迭代

测试 - 第三次迭代

于 2013-10-03T01:15:05.547 回答
0

这应该有效。你只需要弄清楚不同的轨道有多长:

from itertools import zip_longest as zip

def enc (plain, rails = 3):
    return ''.join (plain [i::rails] for i in range (rails) )

def dec (cypher, rails = 3):
    length = len (cypher)
    lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
    paths = [cypher [sum (lens [:i] ):sum (lens [:i + 1] ) ] for i in range (rails) ]
    return ''.join (''.join (x for x in x if x) for x in zip (*paths) )

plain = 'abcdefghijk'
for i in range (10):
    a = plain [:i]
    b = enc (a)
    c = dec (b)
    print (a, b, c)

应该适用于使用的任意 (>0) 轨数。


编辑:没有 zip_longest:

def enc (plain, rails = 3):
    return ''.join (plain [i::rails] for i in range (rails) )

def dec (cypher, rails = 3):
    length = len (cypher)
    lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
    paths = [cypher [sum (lens [:i]):sum (lens [:i + 1] ) ] for i in range (rails) ]
    maxLen = len (paths [0] )
    paths = [list (path) + ( [] if len (path) == maxLen else [''] ) for path in paths]
    return ''.join (''.join (x) for x in zip (*paths) )

解密说明:

length = len (cypher)

为方便起见,将密码文本的长度存储在局部变量中。

lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]

现在我们计算每条轨道的长度。每个导轨的长度是密码文本的长度除以导轨的数量(在您的情况下为 3),如果长度不能完全整除,则可能是(if部分)加上。1

paths = [cypher [sum (lens [:i] ):sum (lens [:i + 1] ) ] for i in range (rails) ]

现在根据我们刚刚计算的轨道长度将密码文本分割成不同的轨道。

maxLen = len (paths [0] )

一条钢轨的最大长度等于第一条钢轨的长度。

paths = [list (path) + ( [] if len (path) == maxLen else [''] ) for path in paths]

现在在每条太短的导轨末端添加一个空字符,这样所有导轨的长度都相同并且可以拉上拉链。

return ''.join (''.join (x) for x in zip (*paths) )

压缩rails,将每个生成的元组连接成一个字符串,然后将所有这些字符串连接成一个长字符串并返回它。

于 2013-10-03T00:26:50.203 回答