2015-02-06 56 views
0

我有this Python script,它試圖檢測文本文件的字符編碼(在這種情況下,C#.cs源文件,但它們可能是任何文本文件),然後轉換他們從那個字符編碼到UTF-8(沒有BOM)。將一串文件從猜測的編碼轉換爲UTF-8

雖然chardet檢測到的編碼足夠好,並且腳本運行沒有錯誤,但©等字符被編碼爲$。所以我認爲腳本和我在Python 2中對編碼的理解有問題。由於將文件從UTF-8-SIG轉換爲UTF-8有效,我感覺問題在於解碼(讀取)部分,而不是編碼(寫入)部分。

誰能告訴我我做錯了什麼?如果切換到Python 3是一種解決方案,那麼我只需要幫助,就可以瞭解如何將腳本從2.7版轉換爲3.4版。這裏的腳本:

import os 
import glob 
import fnmatch 
import codecs 
from chardet.universaldetector import UniversalDetector 

# from http://farmdev.com/talks/unicode/ 
def to_unicode_or_bust(obj, encoding='utf-8'): 
    if isinstance(obj, basestring): 
     if not isinstance(obj, unicode): 
      obj = unicode(obj, encoding) 
    return obj 

def enforce_unicode(): 
    detector = UniversalDetector() 

    for root, dirnames, filenames in os.walk('.'): 
     for filename in fnmatch.filter(filenames, '*.cs'): 
     detector.reset() 
     filepath = os.path.join(root, filename) 

     with open(filepath, 'r') as f: 
      for line in f: 
       detector.feed(line) 
       if detector.done: break 

     detector.close() 
     encoding = detector.result['encoding'] 

     if encoding and not encoding == 'UTF-8': 
      print '%s -> UTF-8 %s' % (encoding.ljust(12), filepath) 
      with codecs.open(filepath, 'r', encoding=encoding) as f: 
       content = ''.join(f.readlines()) 

      content = to_unicode_or_bust(content) 

      with codecs.open(filepath, 'w', encoding='utf-8') as f: 
       f.write(content) 

enforce_unicode() 

我試圖寫入文件前做content = content.decode(encoding).encode('utf-8'),但失敗,出現以下錯誤:

/usr/local/.../lib/python2.7/encodings/utf_8_sig.py:19: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal 
    if input[:3] == codecs.BOM_UTF8: 
Traceback (most recent call last): 
    File "./enforce-unicode.py", line 48, in <module> 
    enforce_unicode() 
    File "./enforce-unicode.py", line 43, in enforce_unicode 
    content = content.decode(encoding).encode('utf-8') 
    File "/usr/local/.../lib/python2.7/encodings/utf_8_sig.py", line 22, in decode 
    (output, consumed) = codecs.utf_8_decode(input, errors, True) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa9' in position 87: ordinal not in range(128) 

想法?

回答

2

chardet只是檢測到編解碼器錯了,您的代碼是正確的。字符檢測是基於統計,啓發式和普通猜測,這不是一個萬無一失的方法。

例如,Windows 1252 codepage非常接近到Latin-1編解碼器;使用一種編碼編碼的文件可以在其他編碼中無差錯地解碼。檢測一個控制代碼或另一個歐元符號之間的區別通常需要人看着結果。

我會記錄每個文件的chardet猜測,如果該文件被錯誤地重新編碼,您需要看看其他編解碼器可能會接近。所有的1250系列代碼頁看起來都很相似。

+0

我明白了。但即使在我知道原始文件位於CP1252中且正確檢測到的情況下,轉換也會失敗。 ©符號被轉換成垃圾。 – 2015-02-08 09:21:16

+0

@asbjornu你如何顯示文件?用什麼工具打開它?你製作的其他代碼並不是在混淆任何東西。你能給我們說明問題的示例字節嗎?我放入,檢測到編解碼器以及最終寫入的字節。 – 2015-02-08 10:03:07

+0

我最終用C#解決了這個問題,但我會接受你的答案,因爲你很可能是正確的。謝謝! – 2016-01-04 09:27:25

相關問題