2008-11-06 5 views
15

Piszę niektóre programy do przetwarzania poczty w Pythonie, które napotykają dziwne bajty w polach nagłówka. Podejrzewam, że to po prostu zniekształcona poczta; sama wiadomość twierdzi, że jest nas-ascii, więc nie sądzę, że istnieje prawdziwe kodowanie, ale chciałbym wydobyć ciąg znaków Unicode zbliżony do oryginalnego bez rzucania UnicodeDecodeError.Czy istnieje funkcja biblioteki Python, która próbuje odgadnąć kodowanie znaków niektórych bajtów?

Poszukuję funkcji, która ma str i opcjonalnie kilka podpowiedzi, a jej darndest daje mi z powrotem unicode. Mógłbym oczywiście napisać, ale jeśli taka funkcja istnieje, autor prawdopodobnie pomyślał nieco głębiej o tym, jak najlepiej to osiągnąć.

Wiem również, że projekt Pythona preferuje jawne i niejawne oraz że standardowa biblioteka ma na celu uniknięcie ukrytej magii w dekodowaniu tekstu. Chcę tylko wyraźnie powiedzieć "śmiało i zgadnij".

Odpowiedz

12

O ile mi wiadomo, standardowa biblioteka nie ma funkcji, choć napisanie jej zgodnie z powyższym opisem nie jest trudne. Myślę, że prawdziwą rzeczą, której szukałem, był sposób dekodowania ciągu znaków i zagwarantowania, że ​​nie wyrzuci wyjątku. Parametr errors do string.decode to robi.

def decode(s, encodings=('ascii', 'utf8', 'latin1')): 
    for encoding in encodings: 
     try: 
      return s.decode(encoding) 
     except UnicodeDecodeError: 
      pass 
    return s.decode('ascii', 'ignore') 
+1

Można pominąć przypadek "ascii" na końcu i po prostu użyć 'latin1', ponieważ' latin1' dekoduje wszystkie 256 bajtowe wartości bez błędu. –

20

Możesz być zainteresowany Universal Encoding Detector.

+0

+1 za bycie 5 sekund szybszy ode mnie :-) –

+0

Naprawdę użyteczne, dzięki. Ale nie w standardowej bibliotece. – Nick

18

+1 dla modułu chardet (zalecane przez @insin).

To nie jest w bibliotece standardowej, ale łatwo można go zainstalować za pomocą następującego polecenia:

$ pip install chardet 

Example:

>>> import chardet 
>>> import urllib 
>>> detect = lambda url: chardet.detect(urllib.urlopen(url).read()) 
>>> detect('http://stackoverflow.com') 
{'confidence': 0.85663169917190185, 'encoding': 'ISO-8859-2'}  
>>> detect('https://stackoverflow.com/questions/269060/is-there-a-python-lib') 
{'confidence': 0.98999999999999999, 'encoding': 'utf-8'} 

Zobacz Installing Pip jeśli nie masz.

+1

Czy nie uderzyło cię, że "ISO-8859-2" było nonsensem? –

+0

@John Machin: Tak, było. Edukacja ma pokazać, że nie powinniście ślepo jej ufać. Obecne wyniki są różne (odpowiednio "utf-8" i "ascii"). – jfs

1

Najlepszym sposobem na zrobienie tego, co znalazłem, jest iteracyjne próbowanie odkodowania potencjalnego z każdym z najczęstszych kodowań wewnątrz bloku próba oprócz bloku.

Powiązane problemy