在 Python 中与 unicode 作斗争

Struggling with unicode in Python

我正在尝试自动从大量文件中提取数据,它在大多数情况下都有效。遇到非ASCII字符就直接倒下:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 5: ordinal not in range(128)

如何将 'brand' 设置为 UTF-8?我的代码正在从其他东西(使用 lxml)中重新利用,并且没有任何问题。我看过很多关于编码/解码的讨论,但我不明白我应该如何实现它。下面被简化为只包含相关代码 - 我已经删除了其余代码。

i = 0

filenames = [y for x in os.walk("Distributor") for y in glob(os.path.join(x[0], '*.xml'))]

for i in range (len(filenames)):
    pathname = filenames[i]

    fin = open(pathname, 'r')
    with codecs.open(('Assets'+'.log'), mode='w', encoding='utf-8') as f:
        f.write(u'File Path|Brand\n')
        lines = fin.read()
        brand_start = lines.find("Brand Title")
        brand_end = lines.find("/>",brand_start)
        brand = lines [brand_start+47:brand_end-2]
        f.write(u'{}|{}\n'.format(pathname[4:35],brand))

flog.close()

我确信有更好的方法来编写整个内容,但目前我的重点只是试图了解如何让行/读取函数与 UTF-8 一起工作。

您将字节串与 Unicode 值混合;您的 fin 文件对象生成字节串,并且您在此处将其与 Unicode 混合:

f.write(u'{}|{}\n'.format(pathname[4:35],brand))

brand 是一个字节串,被插入到一个 Unicode 格式的字符串中。在那里解码 brand,或者更好的是,使用 io.open()(而不是 codecs.open(),它不像较新的 io 模块那样健壮)来管理 两个 你的文件:

with io.open('Assets.log', 'w', encoding='utf-8') as f,\
        io.open(pathname, encoding='utf-8') as fin:
    f.write(u'File Path|Brand\n')
    lines = fin.read()
    brand_start = lines.find(u"Brand Title")
    brand_end = lines.find(u"/>", brand_start)
    brand = lines[brand_start + 47:brand_end - 2]
    f.write(u'{}|{}\n'.format(pathname[4:35], brand))

您似乎也在手动解析 XML 文件;也许您想使用 ElementTree API 来解析这些值。在那种情况下,您将在没有 io.open() 的情况下打开文件,从而生成字节字符串,以便 XML 解析器可以为您正确地将信息解码为 Unicode 值。

这是我的最终代码,使用了上面的指导。它不漂亮,但它解决了问题。稍后我会使用 lxml 来实现所有功能(因为这是我之前在处理不同的、更大的 xml 文件时遇到的问题):

import lxml
import io
import os

from lxml import etree
from glob import glob

nsmap = {'xmlns': 'thisnamespace'}

i = 0

filenames = [y for x in os.walk("Distributor") for y in glob(os.path.join(x[0], '*.xml'))] 

with io.open(('Assets.log'),'w',encoding='utf-8') as f:
    f.write(u'File Path|Series|Brand\n')

    for i in range (len(filenames)):
        pathname = filenames[i]
        parser = lxml.etree.XMLParser()
        tree = lxml.etree.parse(pathname, parser)
        root = tree.getroot()
        fin = open(pathname, 'r')

        with io.open(pathname, encoding='utf-8') as fin:  

            for info in root.xpath('//somepath'):
                series_x = info.find ('./somemorepath')
                series = series_x.get('Asset_Name') if series_x != None else 'Missing'
                lines = fin.read()
                brand_start = lines.find(u"sometext")
                brand_end = lines.find(u"/>",brand_start)
                brand = lines [brand_start:brand_end-2]
                brand = brand[(brand.rfind("/"))+1:]
                f.write(u'{}|{}|{}\n'.format(pathname[5:42],series,brand))

f.close()

现在会有人过来并在一行中完成所有操作!