Wykorzystanie funkcji unicode () i encode () w Pythonie

83

Mam problem z zakodowaniem zmiennej ścieżki i wstawieniem jej do bazy SQLite . Próbowałem to rozwiązać za pomocą funkcji kodowania („utf-8”), która nie pomogła. Następnie użyłem funkcji unicode (), która daje mi typ unicode .

print type(path)                  # <type 'unicode'>
path = path.replace("one", "two") # <type 'str'>
path = path.encode("utf-8")       # <type 'str'> strange
path = unicode(path)              # <type 'unicode'>

Wreszcie uzyskałem typ unicode , ale nadal mam ten sam błąd, który był obecny, gdy typ zmiennej ścieżki to str

sqlite3.ProgrammingError: Nie możesz używać 8-bitowych bajtów, chyba że używasz text_factory, który może interpretować 8-bitowe bajty (jak text_factory = str). Zdecydowanie zaleca się, aby zamiast tego po prostu przełączyć aplikację na ciągi znaków Unicode.

Czy możesz mi pomóc rozwiązać ten błąd i wyjaśnić prawidłowe użycie encode("utf-8")i unicode()funkcje? Często z tym walczę.

EDYTOWAĆ:

Ta instrukcja execute () spowodowała błąd:

cur.execute("update docs set path = :fullFilePath where path = :path", locals())

Zapomniałem zmienić kodowanie zmiennej fullFilePath , która cierpi na ten sam problem, ale jestem teraz dość zdezorientowany. Należy używać tylko unicode () lub kodowanie ( "UTF-8") lub obu?

Nie mogę użyć

fullFilePath = unicode(fullFilePath.encode("utf-8"))

ponieważ wywołuje ten błąd:

UnicodeDecodeError: kodek „ascii” nie może zdekodować bajtu 0xc5 na pozycji 32: numer porządkowy poza zakresem (128)

Wersja Pythona to 2.7.2

xralf
źródło
gdzie jest kod wywołujący błąd?
newtover
2
Twoje dokładne pytanie zostało już udzielone: ​​[ stackoverflow.com/questions/2392732/… [1]: stackoverflow.com/questions/2392732/…
garnertb Kwietnia
@newtover Edytowałem pytanie.
xralf
czy przekonwertowałeś obie używane zmienne na unicode?
newtover
2
Nauczenie się, jak Python 3 obsługuje tekst i dane, naprawdę pomogło mi wszystko zrozumieć. Dzięki temu łatwo jest zastosować tę wiedzę w Pythonie 2.
Oleh Prypin

Odpowiedzi:

88

Używasz encode("utf-8")nieprawidłowo. Ciągi bajtów Pythona ( strtyp) mają kodowanie, a Unicode nie. Możesz przekonwertować ciąg znaków Unicode na ciąg bajtów języka Python za pomocą uni.encode(encoding), a ciąg bajtów można przekonwertować na ciąg znaków Unicode za pomocą s.decode(encoding)(lub równoważnie unicode(s, encoding)).

Jeśli fullFilePathi pathobecnie są strtypem, powinieneś dowiedzieć się, jak są one kodowane. Na przykład, jeśli bieżącym kodowaniem jest utf-8, użyjesz:

path = path.decode('utf-8')
fullFilePath = fullFilePath.decode('utf-8')

Jeśli to nie pomoże, rzeczywisty problem może polegać na tym, że w execute()wywołaniu nie używasz ciągu znaków Unicode , spróbuj zmienić go na następujący:

cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Andrew Clark
źródło
To stwierdzenie fullFilePath = fullFilePath.decode("utf-8")nadal budzi błąd UnicodeEncodeError: 'ascii' codec can't encode characters in position 32-34: ordinal not in range(128). fullFilePath to kombinacja typu str i string pobranych z kolumny tekstowej tabeli db, która powinna być kodowana w formacie UTF-8.
xralf
Zgodnie z tym, ale może to być UTF-8, UTF-16BE lub UTF-16LE. Czy mogę się jakoś dowiedzieć?
xralf
@xralf, jeśli łączysz różne strobiekty, możesz mieszać kodowania. Czy możesz pokazać wynik print repr(fullFilePath)?
Andrew Clark
Mogę to pokazać tylko przed wywołaniem decode () . Problematyczne znaki to \ u0161 i \ u0165.
xralf
@xralf - Czyli to już Unicode? Spróbuj zmienić wywołanie wykonania na Unicode:cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Andrew Clark
122

strjest reprezentacją tekstu w bajtach, unicodejest reprezentacją tekstu w znakach.

Dekodujesz tekst z bajtów na Unicode i kodujesz Unicode na bajty z pewnym kodowaniem.

To jest:

>>> 'abc'.decode('utf-8')  # str to unicode
u'abc'
>>> u'abc'.encode('utf-8') # unicode to str
'abc'

UPD wrzesień 2020 : Odpowiedź została napisana, gdy używany był głównie Python 2. W Pythonie 3 strzmieniono nazwę na bytesi unicodena str.

>>> b'abc'.decode('utf-8') # bytes to str
'abc'
>>> 'abc'.encode('utf-8'). # str to bytes
b'abc'
newtover
źródło
1
Bardzo dobra odpowiedź, od razu do rzeczy. Chciałbym dodać, że unicodemówi o liter lub symboli, lub bardziej ogólnie: runy natomiast strreprezentuje ciąg bajtów w pewnym kodowania, które należy decode(oczywiście w prawidłowym kodowaniu), aby uzyskać szczegółowe runy
arainone
1
Python 3.8 >>'str' object has no attribute 'decode'
Yohan Obadia
czy masz dokumentację dotyczącą zmiany unicode na str? Nie mogę znaleźć
cikatomo
1
@cikatomo To jedna z kluczowych zmian w Pythonie 3: docs.python.org/3.0/whatsnew/ ...
newtover
1

Upewnij się, że ustawiłeś swoje ustawienia regionalne bezpośrednio przed uruchomieniem skryptu z powłoki, np

$ locale -a | grep "^en_.\+UTF-8"
en_GB.UTF-8
en_US.UTF-8
$ export LC_ALL=en_GB.UTF-8
$ export LANG=en_GB.UTF-8

Dokumenty: man locale, man setlocale.

kenorb
źródło