我正在尝试解析UTF-8 XML文件并将其中的一些部分保存到另一个文件中。问题是,这是我的第一个Python脚本,我对我找到的字符编码问题感到困惑。
我的脚本在尝试将非ascii字符写入文件时立即失败,但它可以将其打印到命令提示符(至少在某种程度上)
这是XML(来自至少重要的部分,它是包含UI字符串的* .resx文件)
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="foo">
<value>bar</value>
</resheader>
<data name="lorem" xml:space="preserve">
<value>ipsum öä</value>
</data>
</root>
这是我的python脚本
from xml.dom.minidom import parse
names = []
values = []
def getStrings(path):
dom = parse(path)
data = dom.getElementsByTagName("data")
for i in range(len(data)):
name = data[i].getAttribute("name")
names.append(name)
value = data[i].getElementsByTagName("value")
values.append(value[0].firstChild.nodeValue.encode("utf-8"))
def writeToFile():
with open("uiStrings-fi.py", "w") as f:
for i in range(len(names)):
line = names[i] + '="'+ values[i] + '"' #varName='varValue'
f.write(line)
f.write("\n")
getStrings("ResourceFile.fi-FI.resx")
writeToFile()
这是追溯:
Traceback (most recent call last): File "GenerateLanguageFiles.py", line 24, in writeToFile() File "GenerateLanguageFiles.py", line 19, in writeToFile line = names[i] + '="'+ values[i] + '"' #varName='varValue' UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in ran ge(128)
我应该如何修复脚本以便正确读写UTF-8字符?我正在尝试生成的文件将用于机器人框架的测试自动化。
答案 0 :(得分:7)
您需要移除对encode()
的调用 - 也就是说,将nodeValue.encode("utf-8")
替换为nodeValue
- 然后将调用更改为open()
with open("uiStrings-fi.py", "w", "utf-8") as f:
这使用了open()
的“Unicode-aware”版本,您需要从codecs
模块导入,因此还要添加
from codecs import open
到文件的顶部。
问题在于,当您调用nodeValue.encode("utf-8")
时,您将Unicode字符串(Python的内部表示形式,可以存储所有Unicode字符)转换为常规字符串(只能存储单字节字符0-255) )。稍后,当您构造要写入输出文件的行时,names[i]
仍然是Unicode字符串,但values[i]
是常规字符串。 Python尝试将常规字符串转换为Unicode,这是更通用的类型,但由于您没有指定显式转换,它使用ASCII编解码器,这是默认值,而ASCII无法处理字节值更大的字符不幸的是,其中一些确实出现在字符串values[i]
中,因为UTF-8编码经常使用那些高范围字节。所以Python抱怨说它看到了一个无法处理的角色。正如我上面所说,解决方案是将转换从Unicode推迟到字节,直到最后一刻,你可以使用支持Unicode的版本open(它将为你处理编码)。
现在我考虑一下,而不是我上面所说的,另一种解决方案是用names[i]
替换names[i].encode("utf-8")
。这样,您也可以将names[i]
转换为常规字符串,而Python没有理由尝试将values[i]
转换回Unicode。虽然,人们可以认为将字符串保存为Unicode对象是好的做法,直到将它们写入文件为止......如果没有别的,我相信unicode
成为Python 3中的默认值。
答案 1 :(得分:0)
XML解析器在读取文件时解码输入的UTF-8编码,然后生成的DOM的所有文本节点和属性都是unicode对象。当您从DOM中选择有趣的数据时,将values
重新编码为UTF-8,但不对names
进行编码。生成的values
数组包含编码的字节字符串,而names
数组仍包含unicode对象。
在抛出编码错误的行中,Python尝试连接这样的unicode名称和字节字符串值。为此,两个值必须是相同的类型,Python尝试将字节字符串values[i]
转换为unicode,但它不知道它是UTF-8编码并且在尝试使用ASCII时失败编解码器。
解决此问题的最简单方法是将所有字符串保留为Unicode对象,并在将它们写入文件时将其编码为UTF-8:
values.append(value[0].firstChild.nodeValue) # encode not yet
...
f.write(line.encode('utf-8')) # but now