Python - Unicode编/解码

3
我该如何在创建数据库输入(s1)、从中加载(s2)并将其正确格式化后传递回文件中,以便传输所有内容?
import time,os,sys,base64
s = "Hello World!\r\nHeyho"
#with s1 i make an input to the database; with s2 I select it -> works most time
s1 = base64.b64encode(s.encode("UTF-8")).decode("UTF-8") #print("Base64 Encoded:", s1)
s2 = base64.b64decode(s1.encode("UTF-8")).decode("UTF-8") #print(s2)

#example that I try to save it in a file:
s3 = "PGhlYWQ+CiAgICA8dGl0bGU+4pa3IEltbW9iaWxpZW4gLSBIw6R1c2VyIC0gV29obnVuZ2VuIC0gZmluZGVuIGJlaSBpbW1vd2VsdC5kZTwvdGl0bGU+"
with open("C:\\Users\\001\\Downloads\\Output.txt", "w") as text_file:
    text_file.write("Ausgabe: %s" % base64.b64decode(s3.encode("UTF-8")).decode("UTF-8")) #with .encode('ascii', 'ignore') i whould delete the signs

日志:

C:\Users\001\Downloads>python trythis.py
Traceback (most recent call last):
  File "trythis.py", line 11, in <module>
    text_file.write("Ausgabe: %s" % base64.b64decode(s3.encode("UTF-8")).decode("UTF-8")) #with .encode('ascii', 'ignore') i whould delelte signs
  File "C:\Users\001\AppData\Local\Programs\Python\Python35\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u25b7' in position 28: character maps to <undefined>

编辑:我正在使用Windows操作系统。

C:\Users\001\Downloads>python -V
Python 3.5.2

文件"C:\Users\001\AppData\Local\Programs\Python\Python35\lib\encodings\cp1252.py"似乎表明,在写入过程中,它试图将您的字符串编码为cp1252(Windows ASCII)。您到底想做什么,因为我看到了许多无关紧要的UTF-8编码/解码。 Python 3已经在后台为您处理了大部分工作,因为字符串默认情况下是unicode。 - WombatPM
@WombatPM,"Windows ASCII" 这个说法是不存在的。ASCII 和 Windows-1252 是两种不同的字符编码。但你关于其他方面的说法是正确的。我猜 s1s2 只是为了演示未能正确解码数据的失败尝试而存在于代码中。只有 s3 是相关的。UTF-8 解码是必要的,因为 Base64 编码的数据实际上是 UTF-8 编码的 HTML 页面的一部分。而且 base64.b64decode() 返回一个 bytes 对象。所以在这种情况下是必要的。 - wovano
谢谢,你说得对。windows-1252对应于代码页1252,其中包括ASCII字符集+西欧扩展ASCII字符集。它早于Unicode,并且在许多基于Windows的工具和系统中通常是默认设置,这些工具和系统在美国销售时往往会隐藏复杂性。如果想要一段有趣的阅读体验,请查看https://www.i18nqa.com/debug/table-iso8859-1-vs-windows-1252.html,了解cp-1252、iso-8859-1、iso-8859-15、utf-8、utf-16和HTML实体之间的相似之处和不同之处,这些不同之处直到很久以后才会被揭示。 - WombatPM
2个回答

3
问题在于你以文本模式打开文件,但没有指定编码方式。在这种情况下,系统使用默认编码方式,而不同的系统可能使用不同的编码方式。
解决方案:在 open() 中指定 encoding 参数。
顺便说一句:为什么要使用 .decode('UTF-8')?虽然它可以工作,但由于数据是 Base64 编码的,我认为使用 ASCII 解码更有意义。此外,你应该只在 I/O 边界处进行编码/解码(因此在写入文件时),尽管在这种情况下你可能只是出于测试/演示目的进行了编码/解码。
更新:
显然,你的 Base64 编码数据也是 UTF-8 编码的(先是 UTF-8,然后是 Base64),所以你需要先进行 Base64 解码,然后再进行 UTF-8 解码。
以下是一个可移植、可工作的示例:
import base64

b64_encoded_text = 'PGhlYWQ+CiAgICA8dGl0bGU+4pa3IEltbW9iaWxpZW4gLSBIw6R1c2VyIC0gV29obnVuZ2VuIC0gZmluZGVuIGJlaSBpbW1vd2VsdC5kZTwvdGl0bGU+'
decoded_text = base64.b64decode(b64_encoded_text).decode('utf-8')

with open('Output.txt', 'wt', encoding='utf-8') as text_file:
    text_file.write('Ausgabe: %s' % decoded_text)

虽然直接将原始二进制(UTF-8编码)数据写入文件更加简单:
import base64

b64_encoded_text = 'PGhlYWQ+CiAgICA8dGl0bGU+4pa3IEltbW9iaWxpZW4gLSBIw6R1c2VyIC0gV29obnVuZ2VuIC0gZmluZGVuIGJlaSBpbW1vd2VsdC5kZTwvdGl0bGU+'

with open('Output.txt', 'wb') as file:
    # file.write(b'Ausgabe: ')  # uncomment if really needed
    file.write(base64.b64decode(b64_encoded_text))

0

404pio似乎是正确的。在我的系统中,您的代码在Python 3下运行良好。可能发生的情况是当您运行python trythis.py时,Windows会将Python 2作为默认值。

您可以在以下目录中找到Python 3安装文件:

C:\ Users \ YourUserName \ AppData \ Local \ Programs \ Python \

该目录下应该有一个名为Python37-32或类似名称的文件夹。可以通过在命令提示符中指定完整路径来使用该文件夹中的bin目录中的Python 3二进制文件。

C:\Users\YourUserName\AppData\Local\Programs\Python\Python37-32\bin\python trythis.py

或者将该文件夹添加到您的PATH环境变量中(并从中删除Python 2路径)。

修改路径变量的链接 https://www.java.com/en/download/help/path.xml


1
OP已经证明她正在使用Python 3.5.2,而回溯也证实了这一点。我还缺少一个解释为什么Python 2会导致这个特定的错误。你尝试使用Python 2运行它了吗?代码在你的系统上正常运行的原因可能是你的系统具有不同的文本编码。OP正在使用Windows-1252。也许你正在运行Linux(很可能使用UTF-8),或者生活在一个具有不同系统编码的国家。 - wovano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接