【问题标题】:Python: How to preserve Ä,Ö,Ü when writing to filePython:写入文件时如何保留 Ä,Ö,Ü
【发布时间】:2012-07-18 08:40:51
【问题描述】:

我在 Python 中打开 2 个文件,更改和替换其中的一些内容,并将新输出写入第三个文件。 我的 2 个输入文件是 XML,以“UTF-8 without BOM”编码,其中包含德语 Ä、Ö、Ü 和 ß。 当我在 Notepad++ 中打开我的输出 XML 文件时,没有指定编码(即“编码”选项卡中没有检查编码)。我的 Ä,Ö,Ü 和 ß 变成了类似的东西

ü

当我在 Python 中创建输出时,我使用

with open('file', 'w') as fout:
  fout.write(etree.tostring(tree.getroot()).decode('utf-8'))

我应该怎么做?

【问题讨论】:

  • 写入文件时,你想encode,而不是decode
  • 问题是ü 是否不仅是使用 XML 文件时在 ASCII 之外显示字符的 Notepad++ 方式,还是序列是否在输入文件内。见我的评论stackoverflow.com/a/11539528/1346705

标签: python encoding utf-8


【解决方案1】:

我认为这应该可行:

import codecs

with codecs.open("file.xml", 'w', "utf-8") as fout:
    # do stuff with filepointer

【讨论】:

  • 在我的例子中,这返回了一个“TypeError: Can't convert 'bytes' object to str implicitly”
【解决方案2】:

使用'utf-8' 字符编码将ElementTree 对象tree 写入名为'file' 的文件:

tree.write('file', encoding='utf-8')

【讨论】:

  • 这可能取决于输入文件的打开方式。请参阅我的评论stackoverflow.com/a/11539528/1346705。我不确定这里,但它可能对你有用。
  • @pepr: 'file' 不是文件对象,而是这里的文件名。 ElementTree 自己负责。这里没有意外。
  • @J.F.Sebastian:我注意到了这一点。但在这种情况下,ElementTree 以二进制模式打开文件。请参阅我的评论。
  • @pepr:我的答案中的代码按原样工作。它不依赖于任何东西。从您已将其包含在答案中这一事实来看,您可能也认为它有效。
【解决方案3】:

在写入原始字节串时,您希望以二进制模式打开文件:

with open('file', 'wb') as fout:
    fout.write(xyz)

否则open call 会以文本模式打开文件并需要 unicode 字符串,然后会为您编码。

要解码,就是解释编码(如 utf-8),输出是 unicode 文本。如果您确实想先解码,请在以文本模式打开文件时指定编码:

with open(file, 'w', encoding='utf-8') as fout:
    fout.write(xyz.decode('utf-8'))

如果您不指定编码,Python 将使用默认值,这通常是一件坏事。请注意,由于您已经拥有 UTF-8 编码的字节字符串开始,这实际上是无用的。

请注意,python 文件操作永远不会将现有的 unicode 点转换为 XML character entities(例如 ü),您拥有的其他代码可以这样做,但您没有与我们分享。

我发现 Joel Spolsky's article on Unicode 在理解编码和 unicode 方面非常宝贵。

【讨论】:

  • 如果xyz 已经是一个字节串,那么xyz.encode 可能会损坏它。
  • @J.F.Sebastian:当然,但在这种情况下解码也无济于事。我们对 OP 的代码知之甚少,无论如何都无法正确回答这个问题; decode 感觉就像 OP 在不理解的情况下解决问题,因此链接到 Unicode 文章。
  • 我收到“AttributeError: 'bytes' object has no attribute 'encode'”。我稍微调整了代码以使其更具体。
  • 如果你已经有一个字节串,就不需要编码(也不需要解码)。
  • 我很困惑。如果我使用解码,我的东西实际上会被写入输出文件。但如果我什么都不用,我会收到“TypeError: must be str, not bytes”。
【解决方案4】:

对 Python 2 的 xml.etree.ElementTree 及其函数 parse() 的一些解释。该函数将源作为第一个参数。或者它可以是一个打开的文件对象,也可以是一个文件名。该函数创建ElementTree 实例,然后将参数传递给tree.parse(...),如下所示:

def parse(self, source, parser=None):
    if not hasattr(source, "read"):
        source = open(source, "rb")
    if not parser:
        parser = XMLParser(target=TreeBuilder())
    while 1:
        data = source.read(65536)
        if not data:
            break
        parser.feed(data)
    self._root = parser.close()
    return self._root

你可以从第三行猜到,如果传递了文件名,文件将以二进制模式打开。这样,如果文件内容采用 UTF-8 格式,则您正在处理具有 UTF-8 编码的二进制内容的元素。如果是这种情况,您应该同时以二进制模式打开输出文件

另一种可能性是使用codecs.open(filename, encoding='utf-8') 打开输入文件,并将打开的文件对象传递给xml.etree.ElementTree.parse(...)。这样,ElementTree 实例将使用 Unicode 字符串,并且您应该在写回内容时将结果编码为 UTF-8。如果是这种情况,您也可以使用 codecs.open(...) 和 UTF-8 进行书写。您可以将打开的输出文件对象传递给提到的tree.write(f)您让tree.write(filename, encoding='utf-8')为您打开文件。

【讨论】:

    猜你喜欢
    • 2015-05-04
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 2020-11-10
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多