简体   繁体   English

Python文本加密:rot13

[英]Python text encryption: rot13

I am currently doing an assignment that encrypts text by using rot 13, but some of my text wont register. 我目前正在执行一项任务,该任务使用rot 13加密文本,但是我的某些文本不会注册。

# cgi is to escape html
# import cgi

def rot13(s):
    #string encrypted
    scrypt=''
    alph='abcdefghijklmonpqrstuvwxyz'
    for c in s:
        # check if char is in alphabet
        if c.lower() in alph:
            #find c in alph and return its place
            i = alph.find(c.lower())

            #encrypt char = c incremented by 13
            ccrypt = alph[ i+13 : i+14 ]

            #add encrypted char to string
            if c==c.lower():
                scrypt+=ccrypt
            if c==c.upper():
                scrypt+=ccrypt.upper()

        #dont encrypt special chars or spaces
        else:
            scrypt+=c

    return scrypt
    # return cgi.escape(scrypt, quote = True)


given_string = 'Rot13 Test'
print rot13(given_string) 

OUTPUT: 输出:

13 r
[Finished in 0.0s]

Hmmm, seems like a bunch of things are not working. 嗯,似乎一堆东西都没有用。 Main problem should be in ccrypt = alph[ i+13 : i+14 ] : you're missing a % len(alph) otherwise if, for example, i is equal to 18 , then you'll end out of the list boundary. 主要问题应该在ccrypt = alph[ i+13 : i+14 ] :您缺少% len(alph)否则,例如,如果i等于18 ,那么您将超出列表边界。 In your output, in fact, only e is encoded to r because it's the only letter in your test string which, moved by 13, doesn't end out of boundary. 实际上,在您的输出中,只有e编码为r因为它是测试字符串中唯一一个字母,该字母移动13不会超出边界。

The rest of this answer are just tips to clean the code a little bit: 该答案的其余部分只是一些清洁代码的提示:

  • instead of alph='abc.. you can declare an import string at the beginning of the script and use a string.lowercase 而不是alph='abc..你可以申报import string在脚本的开头和使用string.lowercase
  • instead of using string slicing, for just one character it's better to use string[i] , gets the work done 与其使用字符串切片,不如只使用一个字符,最好使用string[i]来完成工作
  • instead of c == c.upper() , you can use builtin function if c.isupper() ... . if c.isupper() ...可以使用内置函数来代替c == c.upper()

The trouble you're having is with your slice. 您遇到的麻烦是切片问题。 It will be empty if your character is in the second half of the alphabet, because i+13 will be off the end. 如果您的字符位于字母的后半部分,则该字符为空,因为i+13不在结尾。 There are a few ways you could fix it. 有几种方法可以修复它。

The simplest might be to simply double your alphabet string (literally: alph = alph * 2 ). 最简单的方法是简单地将您的字母字符串加倍(字面意思是: alph = alph * 2 )。 This means you can access values up to 52, rather than just up to 26. This is a pretty crude solution though, and it would be better to just fix the indexing. 这意味着您最多可以访问52个值,而不是最多26个值。不过,这是一个很粗糙的解决方案,最好只修复索引。

A better option would be to subtract 13 from your index, rather than adding 13. Rot13 is symmetric, so both will have the same effect, and it will work because negative indexes are legal in Python (they refer to positions counted backwards from the end). 更好的选择是从索引中减去13,而不是加13。Rot13是对称的,因此两者具有相同的效果,并且将起作用,因为负索引在Python中是合法的(它们指的是从末尾开始倒数的位置) )。

In either case, it's not actually necessary to do a slice at all. 无论哪种情况,实际上都没有必要做任何切片。 You can simply grab a single value (unlike C, there's no char type in Python, so single characters are strings too). 您可以简单地获取一个值(与C不同,Python中没有char类型,因此单个字符也是字符串)。 If you were to make only this change, it would probably make it clear why your current code is failing, as trying to access a single value off the end of a string will raise an exception. 如果仅进行此更改,则可能会弄清楚为什么当前代码失败,因为尝试从字符串末尾访问单个值将引发异常。

Edit: Actually, after thinking about what solution is really best, I'm inclined to suggest avoiding index-math based solutions entirely. 编辑:实际上,在考虑了哪种解决方案真正是最好的之后,我倾向于建议完全避免使用基于索引算法的解决方案。 A better approach is to use Python's fantastic dictionaries to do your mapping from original characters to encrypted ones. 更好的方法是使用Python出色的字典来完成从原始字符到加密字符的映射。 You can build and use a Rot13 dictionary like this: 您可以像这样构建和使用Rot13词典:

alph="abcdefghijklmnopqrstuvwxyz"
rot13_table = dict(zip(alph, alph[13:]+alph[:13])) # lowercase character mappings
rot13_table.update((c.upper(),rot13_table[c].upper()) for c in alph) # upppercase

def rot13(s):
    return "".join(rot13_table.get(c, c) for c in s) # non-letters are ignored

This line 这条线

ccrypt = alph[ i+13 : i+14 ]

does not do what you think it does - it returns a string slice from i+13 to i+14 , but if these indices are greater than the length of the string, the slice will be empty: 不会执行您认为的操作-它从i+13i+14返回一个字符串切片,但是如果这些索引大于字符串的长度,则该切片将为空:

"abc"[5:6] #returns ''

This means your solution turns everything from n onward into an empty string, which produces your observed output. 这意味着您的解决方案将从n开始的所有内容转换为空字符串,从而产生观察到的输出。

The correct way of implementing this would be (1.) using a modulo operation to constrain the index to a valid number and (2.) using simple character access instead of string slices, which is easier to read, faster, and throws an IndexError for invalid indices, meaning your error would have been obvious. 正确的实现方式是(1.)使用模运算将索引约束为有效数字,以及(2.)使用简单字符访问而不是字符串切片,这更易于阅读,更快并且抛出IndexError对于无效的索引,这意味着您的错误将很明显。

ccrypt = alph[(i+13) % 26]

First thing that may have caused you some problems - your string list has the n and the o switched, so you'll want to adjust that :) As for the algorithm, when you run: 可能引起一些问题的第一件事-字符串列表的no切换,因此您需要进行调整:)至于算法,在运行时:

ccrypt = alph[ i+13 : i+14 ]

Think of what happens when you get 25 back from the first iteration (for z ). 想一想当您从第一次迭代中得到25时(对于z )会发生什么。 You are now looking for the index position alph[38:39] (side note: you can actually just say alph[38] ), which is far past the bounds of the 26-character string, which will return '' : 现在,您正在寻找索引位置alph[38:39] (旁注:您实际上可以说alph[38] ),它远远超出了26个字符的字符串的界限,该字符串将返回''

In [1]: s = 'abcde'

In [2]: s[2]
Out[2]: 'c'

In [3]: s[2:3]
Out[3]: 'c'

In [4]: s[49:50]
Out[4]: ''

As for how to fix it, there are a number of interesting methods. 至于解决方法,有许多有趣的方法。 Your code functions just fine with a few modifications. 您的代码只需进行一些修改即可正常运行。 One thing you could do is create a mapping of characters that are already 'rotated' 13 positions: 您可以做的一件事是创建已经“旋转” 13个位置的字符映射:

alph = 'abcdefghijklmnopqrstuvwxyz'
coded = 'nopqrstuvwxyzabcdefghijklm'

All we did here is split the original list into halves of 13 and then swap them - we now know that if we take a letter like a and get its position ( 0 ), the same position in the coded list will be the rot13 value. 我们在这里所做的全部工作是将原始列表分成13个一半,然后交换它们-现在我们知道,如果我们采用a这样a字母并获得其位置( 0 ),则编码列表中的相同位置将是rot13值。 As this is for an assignment I won't spell out how to do it, but see if that gets you on the right track (and @Makoto's suggestion is a perfect way to check your results). 因为这是一项任务,所以我不会详细说明如何执行任务,但是请查看它是否使您步入正轨(@Makoto的建议是检查结果的理想方法)。

If you're doing this as an exercise for a course in Python, ignore this, but just saying... 如果您将其作为Python课程的练习,请忽略此内容,只是说...

>>> import codecs
>>> codecs.encode('Some text', 'rot13')
'Fbzr grkg'
>>> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM