如何将包含 unicode 的 2d 数组保存到/从.txt文件 [Python] [编码问题][utf8]



所以我遇到的基本问题是当我写入txt文件时,Unicode字符\u2656变成这个b'\xe2\x99\x96'(我相信这是字节码?然后当我读取文件时,我无法将其解码回\u2656

Board_visual只是一个 2D 数组,其中每个项目都是 unicode 字符或 None 类型(空方块)。它用于表示我的tkinter gui使用的棋盘上棋子的位置。实际的棋子是对象,所以这只是表示棋子的 unicode 字符。

示例board_visual内容

['♖', '♘', '♗', '♔', '♕', '♗', '♘', '♖']
['♙', None, '♙', '♙', '♙', '♙', '♙', '♙']
[None, '♙', None, None, None, None, None, None]
[None, None, None, None, None, None, None, None]
[None, None, None, '♟', None, None, None, None]
[None, None, None, None, None, None, None, None]
['♟', '♟', '♟', None, '♟', '♟', '♟', '♟']
['♜', '♞', '♝', '♚', '♛', '♝', '♞', '♜']

这是我使用的代码:

def save():
filename=input("Enter the name of the file")
myFile=open(str(filename)+".txt","w")
for i in board_visual:
for j in i:
myFile.write(str(str(j).encode('utf8')))
myFile.write("n")
myFile.close()

它给出了以下文件格式(在.txt文件中):

b'xe2x99x97'
b'xe2x99x98'
b'xe2x99x96'
b'None'
b'xe2x99x99'
b'xe2x99x99'
b'None'
b'xe2x99x99'
b'xe2x99x99'
b'xe2x99x99'
b'xe2x99x99'
b'None'
...

然后我尝试阅读它

def load():
global board_visual
global board
filename=input("Enter the name of the file")
myFile=open(str(filename)+".txt","r", encoding='utf8')
index=0
index2=0
for i in myFile:
if i!="b'None'n":
i=i.strip("n")
board_visual[index//8][index%8]=i#places it into the 8*8 grid
else:
board_visual[index//8][index%8]=None
index=index+1
myFile.close()

这个网站上的一些帖子提到使用 .decode,但这仅适用于 python 2 我使用的是 python 3.3,当我没有任何 unicode 字符时,这个程序运行良好。这意味着问题一定出在编码上,但这是我第一次使用它,我似乎无法正确解码它。我已经浏览了网站上的许多类似问题,但没有一个解决方案对我有用(许多解决方案适用于Python 2) 我最初在写入文件时尝试不使用 .encode(utf8),但这给了我错误:UnicodeEncodeError:"charmap"编解码器无法在位置 0 中编码字符"\u2656":字符映射到 从研究错误我添加了 .encode(utf8),但这会导致在程序中将其解码回 unicode 时出现问题。 我也使用了 unicode(i),但这是一个未知的命令。

由于只有 12 个不同的字符,我可以创建一个 if/elif 语句来检查它们并自行转换它们,但这显然是一个非常糟糕的解决方案。

我对编程相当陌生,python是我唯一的语言,这用于国际象棋游戏引擎。(我的第一个大项目) 我不确定我错过了什么。任何帮助将不胜感激,我希望我的帖子符合要求。如果有一个网站可以推荐来帮助我了解 python 编码,那也很棒,我似乎无法让它工作。

提前致谢

这应该适合您。 在 Python 3.6 上测试

chess = "♔ ♕ ♖ ♗ ♘ u2655 u2656 u2657 u2658 u2659 u265a"
f = open('file', 'wb')
f.write(chess.encode('utf8'))
f.close()
f = open('file', 'rb')
print (f.read().decode('utf-8'))

这当然不是你真正想要做的,但ast.literal_eval能够反转 utf8 编码数据的序列化:

>>> t = r"b'xe2x99x96'"
>>> print(t)
b'xe2x99x96'
>>> print(ast.literal_eval(r"b'xe2x99x96'").decode())
♖
>>> print(hex(ord(ast.literal_eval(r"b'xe2x99x96'").decode())))
0x2656

但这真的很丑陋,你应该要么使用 json,要么直接依靠 Python 的能力来自动编码和解码 utf-8 中的 unicode:

for j in i:
myFile.write(j)
myFile.write("n")

正如@juanpa.Arrivillaga在他的评论中所建议的那样

代码中的实际问题是这部分:

str(str(j).encode('utf8'))

通常,您的代码充斥着对str的调用。它们中的大多数是不必要的和令人困惑的,但无害。但这个是有害的。

在交互式解释器上尝试表达式的每个部分可能会有所帮助。如果j是字符串,则str(j)是同一字符串的副本。然后str(j).encode(‘utf8’)是一个保存该字符串的 UTF-8 编码的bytes。然后str(str(j).encode(‘utf8’))是该字节对象的字符串表示形式,它将是一个字母 b 和一些引号,中间有一堆反斜杠转义。这就是您最终写入文件的内容。

如果你只使用j.encode(‘utf8’),这个问题会消失,但它可能只是许多问题中的第一个。最有可能的是,下一个是你打开了一个文本模式文件,但随后尝试向其写入编码bytes而不是字符串。您可以通过不进行编码而仅使用j来解决此问题。等等。

更一般地说,你需要了解你在做什么,然后你才希望Python知道你想做什么。如果你不知道为什么要在某个地方打电话给str,你为什么要打电话呢?

在 Python(3.0 及更高版本)中,您不应该到处处理编码。只需指定一次编码,尽可能靠近边缘。特别是,如果你想将一些 Unicode 写入 UTF-8 文件,只需将 Unicode 写入 UTF-8 文件:

s = ‘u1234u2345’
with open(‘myfile.txt’, ‘w’, encoding=‘utf-8’) as f:
f.write(s)

就是这样。无需调用encodedecodestr,也无需在任何地方处理bytes对象。

最新更新