2015-04-20 74 views
1

我試圖從大量文件中自動提取數據,並且它在大多數情況下都能正常工作。當它遇到非ASCII字符時,它就會崩潰:用Python中的unicode掙扎

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

如何將我的品牌設置爲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的工作。

+0

您應該顯示完整的錯誤,包括回溯。除了別的,它說錯誤發生在哪一行。 –

+1

http://nedbatchelder.com/text/unipain.html – tripleee

回答

1

您正在混合使用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值。

+0

謝謝,解決了根本問題。最後一個問題是它會覆蓋文件內容,所以我只得到兩行「File Path | Brand」和「SYNT0000000000001045-20150331T095311Z | Something Here |」。我將'w'更改爲'a',但每隔一行重複一次文件路徑|品牌。建議? – Nick

+1

@Nick:爲什麼不在任何循環的外部創建文件? –

+0

另外,你是對的。我已經使用lxml傳遞xml的一部分。這應該是一個快速和骯髒的解決方案,因爲我不知道如何解決這個特定的場景(結構中有許多類似的孩子)。一旦我解決了立即需要從文件中獲取信息的問題,我將打開一個單獨的線程以正常工作。 – Nick

0

這是我最後的代碼,使用上面的指導。這不太好,但它解決了這個問題。我會看得到它全部採用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() 

有人將現在沿過來做全部在一行!