替代换行符?python

0 投票
7 回答
11459 浏览
提问于 2025-04-15 11:32

我想找一种方法,用一个字符来表示换行符'\n'。我正在写一个程序,使用字典来“加密”文本。因为字典中每个字符都有对应的表示,所以当我的程序遇到字符串中的换行符时,它却把它当成了'\'和'n'两个字符来读取。这让我遇到了问题。有没有其他方法可以用一个字符来表示换行呢?

下面是我的代码,如果缩进有点乱我很抱歉。我不太明白怎么在这个窗口里输入代码。:)

##################################
#This program will take an input and encrypt it or decrypt it
#A cipher is used to transform the text, which can either be
#input or from a text file.
#The cipher can be any letter a-z, as well as most commonly used special characters
#numbers and spaces are not allowed.
#For the text, a-z, most special characters, space, and new line may be used.
#no numbers can be encrypted.
##################################

#These three dictionaries are used during the encryption process.
keyDict={'a': 17,'b': 3,'c':16,'d':26,'e':6,'f':19,'g':10,'h':12,
         'i':22,'j':8,'k': 11,'l':2,'m':18,'n':9,'o':23,'p':7,
         'q':5,'r': 20,'s': 1,'t': 24,'u':13,'v':25,'w':21,'x':15,
         'y':4,'z': 14, ' ':42, '.':0,'!': 27, '@': 34, '#': 35, '%': 37,
         '$': 36, "'": 33,'&': 39, '*': 40, ',': 29, '.': 30, '~': 41, ';': 31,
         ':': 32, '?': 28, '^': 38}

refDict2={' ': 43,  'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4, 'g': 7, 'f': 6, 'i': 9,
         'h': 8, 'k': 11, 'j': 10, 'm': 13, 'l': 12, 'o': 15, 'n': 14, 'q': 17,'\n': 42,
         'p': 16, 's': 19, 'r': 18, 'u': 21, 't': 20, 'w': 23, 'v': 22, 'y': 25,
         'x': 24, 'z': 26, ' ':0, '!': 27, '@': 34, '#': 35, '%': 37, '$': 36, "'": 33,
          '&': 39, '*': 40, ',': 29, '.': 30, '~': 41, ';': 31, ':': 32, '?': 28, '^': 38}

refDict={0: ' ', 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i',
         10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 42:'\n',
         18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z', 43:' ',
         32: ':', 33: "'", 34: '@', 35: '#', 36: '$', 37: '%', 38: '^', 39: '&', 40: '*',
         41: '~', 27: '!', 28: '?', 29: ',', 30: '.', 31: ';'}


#switch1 reverses a list. It is its own inverse, so we don't need an unswitch function. 
def switch1(l):
    return l[::-1]



#switch2 takes a list as input and moves every fourth entry to the front
#so switch2([a,b,c,d,e,f,g]) returns ([a,e,b,c,d,f,g])
#unswitch2 undoes this, so unswitch2([a,e,c,d,f,g]) returns [a,b,c,d,e,f,g]

def switch2(l):
    List4 = []
    ListNot4 = []
    for i in range(0,len(l)):
        if i%4 == 0:
            List4.append(l[i])
        else:
            ListNot4.append(l[i])
    return List4+ListNot4

def unswitch2(l):
    num4 = len(l)/4 + 1
    fixedList = l[num4:]
    for i in range (0,num4):
        fixedList.insert(4*i,l[i])
    return fixedList



#switch3 takes a list as input and returns a list with the first half moved to the end.
#so switch3([a,b,c,d,e,f]) returns [d,e,f,a,b,c]
#for lists of odd length, switch3 puts the separation closer to the beginning of the list, so the
#middle entry becomes the first entry.
#For example, switch3([a,b,c,d,e,f,g]) returns [d,e,f,g,a,b,c]

def switch3(l):
    return l[len(l)/2:] + l[:len(l)/2]

def unswitch3(l):
    if len(l)%2==0:
        return switch3(l)
    else:
        return l[len(l)/2+1:] + l[:len(l)/2+1]




##################################
#This is the Crypt function.
##################################
def Crypt(text, cipher):
    counter=0
    text=text.lower()
    cipher=cipher.lower()
    keyValue=[]
    textValue=[]
    newValue=[]
    newString=''
    for letter in cipher:
        keyValue.append(keyDict[letter])

    for letter in text:
        textValue.append(refDict2[letter])

    for num in textValue:
        newValue.append(num+keyValue[counter%len(keyValue)])
        counter+=1

    newValue = switch1(newValue)
    newValue = switch2(newValue)
    newValue = switch3(newValue)

    for num in newValue:
        newString+=refDict[num%43]

    return newString

##################################
#This is the Decrypt function
##################################
def Decrypt(encryptedText, cipher):
    counter=0
    cipher=cipher.lower()
    keyValue=[]
    textValue=[]
    finalValue=[]
    finalString=''

    for letter in encryptedText:
        textValue.append(refDict2[letter])

    textValue = unswitch3(textValue)
    textValue = unswitch2(textValue)
    textValue = switch1(textValue)

    for letter in cipher:
        keyValue.append(keyDict[letter])

    for num in textValue:
        finalValue.append((num-keyValue[counter%len(keyValue)])%43)
        counter+=1


    for num in finalValue:
        finalString+=refDict[num]

    return finalString


##################################
#This is the user interface.
##################################

choice=raw_input('Would you like to: 1)Encrypt or 2)Decrypt?  Pick 1 or 2: ')

if choice=='1':
    textType=raw_input("Would you like to: 1)encrypt a text file or 2) input the text to be encrypted? Pick 1 or 2: ")

    if textType=='1':
        cryptName=raw_input( 'Please enter the name of the text file you would like to encrypt(eg. text.txt): ')
        newName=raw_input('Please name the file in which the encrypted text will be stored(eg. secret.txt):' )
        cipher=raw_input("Now enter your personal encryption key(eg. secret code):" )

        cryptFile=open(cryptName, 'r')
        newFile=open(newName, 'w')
        print >> newFile, Crypt(cryptFile.read(),cipher)
        cryptFile.close()
        newFile.close()
        print "Ok, all done!"
    elif textType=='2':
        inputText=raw_input('Ok, please input the text you would like to encrypt(eg. computers rock!): ')
        cipher=raw_input("Now enter your personal encryption key (eg. ultra secret code): ")
        if inputText=='': print 'Oops, no text was entered! Try again!'
        else:
            print Crypt(inputText, cipher)
    else:
        print 'Try again!'

elif choice=='2':
    textType=raw_input("Would you like to:1)decrypt a text file or 2) input the text to be decrypted? Pick 1 or 2: ")
    if textType=='1':
        decryptName=raw_input( 'Please enter the name of the text file you would like to decrypt(eg. text.txt): ')
        newName2=raw_input('Please name the file in which the decrypted text will be stored(eg. secret.txt):' )
        cipher=raw_input("Now enter the encryption key that was used to encrypt the file(eg. secret code):" )
        #Text decrypt
        decryptFile=open(decryptName, 'r')
        newFile2=open(newName2, 'w')
        print>> newFile2, Decrypt(decryptFile.read(),cipher)
        #other stuff
        #textTodecrypt=decryptFile.read()
        #newFile2.writelines(Decrypt(textTodecrypt, cipher))


        decryptFile.close()
        newFile2.close()
        print "Ok, all done!"

    elif textType=='2':
        inputText=raw_input('Ok, please input the text you would like to decrypt(eg. dig&ak:do): ')
        cipher=raw_input("Now enter the encryption key that was used to encrypt the text (eg. ultra secret code): ")
        if inputText=='': print 'Oops, no text was entered! Try again!'
        else:
            print Decrypt(inputText, cipher)

print "Have a nice day!"


#there is an issue with the newline character 

7 个回答

4

我猜你的真正问题不是在于把 \n 读成 '\' 和 'n',因为在内部,Python 应该会自动把 \n 转换成一个字符。

我觉得真正的问题可能是你的换行符实际上是两个字符——回车符('\r')和换行符('\n')。试着同时处理 \r 和 \n,看看这样是否能解决你的问题。

4

我猜问题出在要解密的文本中如果有\n的话,就会出错:

KeyError: \

module body   in untitled at line 166
function Crypt    in untitled at line 94

简单来说,raw_input() 返回的字符串里包含两个字符 \n,而你没有对应的映射,所以就出错了。

最简单的解决办法就是把字面上的字符 \n 替换成 \n 的转义序列。

def Crypt(text, cipher):
    text.replace(r"\n", "\n")
    ... 

原始字符串 r"\n" 创建了一个字符串,里面有字面上的字符 \ 后面跟着 n(这和 "\\n" 是一样的)。

在普通字符串 "\n" 中,它被当作换行的转义序列。所以上面的代码块会把文本中的 \n 替换成换行符。

你可能需要在你的 keyDict 映射中定义一个 "\n" 的映射。

另一种解决方案是使用 text.split(r"\n") 来分割文本,然后分别处理每一行。或者像其他人建议的那样,使用 ord() 来处理每个字符,直接用数字来处理,而不是自己做数字映射。

ord(c) 给定一个长度为一的字符串,返回一个整数,表示这个字符的 Unicode 码点,如果参数是一个 unicode 对象;或者如果参数是一个 8 位字符串,则返回字节的值。例如,ord('a') 返回整数 97,ord(u'\u2020') 返回 8224。这是 chr() 对于 8 位字符串和 unichr() 对于 unicode 对象的反操作。

正如文档所解释的,chr() 是相反的,它会把数字转回 ASCII 或 Unicode 字符:

chr(i) 返回一个字符的字符串,其 ASCII 码是整数 i。例如,chr(97) 返回字符串 'a'。这是 ord() 的反操作。参数必须在 [0..255] 的范围内;如果 i 超出这个范围,会引发 ValueError。

基本上你可以这样做:

def Crypt(text, cipher):
    keyvalue = [ord(x) for x in cipher)
    textvalue = [ord(x) for x in text]

..而不是使用两个 for 循环(列表推导式 基本上和创建一个列表是一样的,遍历文本或密文中的每个字符,每次都添加到列表中)

10

'\n' 是一个字符。它是一个换行符的表示方式,代表着换行。

请把你的问题重新表述得更清楚一些。

[编辑] 我想我知道你的问题是什么。我运行了你的程序,结果很好。你可能是想从命令行把 '\n' 传给你的程序,但这样是行不通的!

你看,如果你给 raw_input() 这个字符串:line1\nline2,它会把 \n 转义成 \\n,变成这样:'line1\\nline2'

所以一个简单的解决办法是把 '\\n' 替换成 '\n':

text.replace('\\n', '\n')

我不太喜欢这个方法,但它能解决你的问题。

更好的方法是像这样读取多行:

input = raw_input('Please type in something: ')
lines = [input]
while input:
    input = raw_input()
    lines.append(input)

text = '\n'.join(lines)

print text

撰写回答