Zacząłem od próby do przechowywania ciągów w SQLite przy użyciu Python i dostał wiadomość:SQLite, Python, Unicode i UTF-non dane
sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.
Ok, przeszedłem do ciągów Unicode. Następnie zacząłem otrzymywać komunikat:
sqlite3.OperationalError: Could not decode to UTF-8 column 'tag_artist' with text 'Sigur Rós'
podczas próby pobrania danych z bazy danych. Badania naukowe i zacząłem go w utf8 kodowania, ale zaczyna Then „Sigur Ros” wyglądać jak „Sigur Rós”
uwaga: Moja konsola została powołana do wyświetlenia w „latin_1” jako @John Machin zauważył.
Co daje? Po przeczytaniu this, opisując dokładnie tę samą sytuację, w której się znajduję, wydaje mi się, że poradą jest zignorowanie drugiej porady i użycie w końcu 8-bitowych bytów.
Nie wiedziałem zbyt wiele o unicode i utf zanim rozpocząłem ten proces. Dowiedziałem się całkiem sporo w ciągu ostatnich kilku godzin, ale nadal nie wiem, czy istnieje sposób, aby poprawnie przekonwertować "ó" z latin-1 na utf-8 i nie manipulować nim. Jeśli tak nie jest, dlaczego sqlite "bardzo polecam" Przełączam swoją aplikację na ciągi Unicode?
zamierzam aktualizować to pytanie z podsumowaniem i jakiś przykład kodu wszystkiego nauczyłem się w ciągu ostatnich 24 godzin tak, że ktoś w moich butach mogą mieć łatwy (ER) przewodnika. Jeśli informacje, które zamieszczam, są błędne lub wprowadzające w błąd w jakikolwiek sposób, proszę powiedz mi, a zaktualizuję, lub jeden z was, starsi faceci, może zaktualizować.
Streszczenie odpowiedzi
Pozwól pierwszym państwie cel jak rozumiem. Celem przetwarzania różnych kodowań, jeśli próbujesz dokonać konwersji między nimi, jest zrozumienie kodowania źródłowego, a następnie przekonwertowanie go na kod Unicode za pomocą tego kodowania źródłowego, a następnie przekonwertowanie go na pożądane kodowanie. Unicode jest podstawą, a kodowanie to odwzorowanie podzbiorów tej bazy. utf_8 ma miejsce na każdy znak w unicode, ale ponieważ nie są one w tym samym miejscu co na przykład latin_1, łańcuch zakodowany w utf_8 i wysłany na konsolę latin_1 nie będzie wyglądał tak, jak oczekujesz. W python proces dotarcia do Unicode i do innego kodowania wygląda następująco:
str.decode('source_encoding').encode('desired_encoding')
czy STR jest już unicode
str.encode('desired_encoding')
SQLite I faktycznie nie chcemy zakodować go ponownie, Chciałem go rozszyfrować i pozostawić w formacie Unicode. Oto cztery rzeczy, o których możesz być świadomy podczas próby pracy z unikodem i kodowaniem w pythonie.
- Kodowanie napisu, z którym chcesz pracować, oraz kodowanie, do którego chcesz go uzyskać.
- Kodowanie systemu.
- Kodowanie konsoli.
- kodowanie pliku źródłowego
opracowania:
(1) Kiedy czytasz ciąg ze źródła, to musi mieć jakieś kodowanie, jak latin_1 lub UTF_8. W moim przypadku otrzymuję ciągi znaków z nazw plików, więc niestety, mógłbym uzyskać jakiekolwiek kodowanie. Windows XP używa UCS-2 (system Unicode) jako natywny typ łańcucha, co wydaje się być dla mnie oszukiwaniem. Na szczęście dla mnie postacie w większości nazw plików nie będą składać się z więcej niż jednego kodu źródłowego i myślę, że wszystkie moje były całkowicie łacińskie_1, całkowicie utf_8, lub po prostu ascii (który jest podzbiorem obu te). Więc po prostu je czytałem i dekodowałem tak, jakby były nadal w latin_1 lub utf_8. Możliwe jednak, że możesz mieć łacińskie_1 i utf_8 oraz dowolne inne znaki zmieszane razem w nazwie pliku w systemie Windows. Czasami te postacie mogą pojawiać się jako pudełka, innym razem wyglądają na zmanipulowane, a innym razem wyglądają poprawnie (znaki akcentowane i inne). Iść dalej.
(2) Python ma domyślne kodowanie systemowe, które jest ustawiane podczas uruchamiania Pythona i nie można go zmienić w czasie wykonywania. Aby uzyskać szczegółowe informacje, patrz here. Podsumowanie brudne ... dobrze tutaj jest plik I dodaje:
kodowania\# sitecustomize.py
\# this file can be anywhere in your Python path,
\# but it usually goes in ${pythondir}/lib/site-packages/
import sys
sys.setdefaultencoding('utf_8')
Ten system to taki, który przyzwyczaja się podczas korzystania z Unicode („str”) Funkcja bez żadnych innych parametrów kodowania. Aby powiedzieć, że w inny sposób, python próbuje zdekodować "str" do Unicode na podstawie domyślnego kodowania systemu.
(3) Jeśli używasz IDLE lub python linii poleceń, myślę, że twoja konsola wyświetli się zgodnie z domyślnym kodowaniem systemu. Używam pydev z eclipse z jakiegoś powodu, więc musiałem przejść do ustawień mojego projektu, edytować właściwości konfiguracji uruchamiania mojego skryptu testowego, przejść do zakładki Common i zmienić konsolę z Latin-1 na utf-8, aby Mogłem wizualnie potwierdzić, że to, co robię, działa.
(4) Jeśli chcesz mieć jakieś sznurki testowych, np
test_str = "ó"
w kodzie źródłowym, a następnie trzeba będzie powiedzieć Pythona jaki rodzaj kodowania używasz w tym pliku. (FYI: kiedy literówka kodowania musiałem CTRL-Z, ponieważ mój plik stał się nieczytelny.) Można to łatwo osiągnąć poprzez umieszczenie linii podobnie jak w górnej części pliku z kodem źródłowym:
# -*- coding: utf_8 -*-
Jeśli don „t mieć te informacje, próby Pythona do analizowania kodu jako ASCII domyślnie, a więc:
SyntaxError: Non-ASCII character '\xf3' in file _redacted_ on line 81, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
gdy program działa poprawnie, lub, jeśli nie używasz konsoli Pythona lub jakąkolwiek inną konsolę wyglądać na wyjściu, prawdopodobnie naprawdę będziesz obchodził tylko # 1 na liście. Domyślne ustawienia systemowe i kodowanie konsoli nie są aż tak ważne, chyba że musisz spojrzeć na wyjście i/lub używasz wbudowanej funkcji unicode() (bez żadnych parametrów kodowania) zamiast funkcji string.decode(). Napisałem funkcję demo, którą wkleję na dno tego gigantycznego bałaganu, który - jak mam nadzieję - poprawnie pokazuje elementy na mojej liście. Oto niektóre dane wyjściowe, gdy uruchamiam znak "ó" za pomocą funkcji demo, pokazując, jak różne metody reagują na znak jako dane wejściowe.Moje kodowanie systemu i wyjście konsoli są zarówno ustawione UTF_8 do tego biegu:
'�' = original char <type 'str'> repr(char)='\xf3'
'?' = unicode(char) ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
'ó' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Teraz mogę zmienić system i kodowanie konsoli latin_1, a ja się tego wyjścia dla tego samego wejścia:
'ó' = original char <type 'str'> repr(char)='\xf3'
'ó' = unicode(char) <type 'unicode'> repr(unicode(char))=u'\xf3'
'ó' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Zwróć uwagę, że znak "oryginalny" wyświetla się poprawnie, a wbudowana funkcja unicode() działa teraz.
Teraz zmieniam dane wyjściowe z konsoli na utf_8.
'�' = original char <type 'str'> repr(char)='\xf3'
'�' = unicode(char) <type 'unicode'> repr(unicode(char))=u'\xf3'
'�' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Tutaj wszystko nadal działa tak samo jak ostatnio, ale konsola nie może poprawnie wyświetlić danych wyjściowych. Itd. Poniższa funkcja wyświetla również więcej informacji, które mogą pomóc komuś w zrozumieniu luki w ich rozumieniu. Wiem, że wszystkie te informacje znajdują się w innych miejscach i są tam dokładniej omówione, ale mam nadzieję, że byłby to dobry punkt wyjścia dla kogoś, kto próbuje uzyskać kodowanie za pomocą pythona i/lub sqlite. Pomysły są świetne, ale czasami kod źródłowy może zaoszczędzić ci dzień lub dwa, próbując dowiedzieć się, jakie funkcje działają.
Nota prawna: Nie jestem ekspertem od kodowania, umieściłem to razem, aby pomóc mojemu zrozumieniu. Ciągle się nad tym zastanawiałem, kiedy prawdopodobnie powinienem zacząć przekazywać funkcje jako argumenty, aby uniknąć tak bardzo zbędnego kodu, więc jeśli mogę, sprawię, że będzie on bardziej zwięzły. Ponadto, utf_8 i latin_1 nie są w żadnym wypadku jedynymi schematami kodowania, są tylko tymi dwoma, z którymi grałem, ponieważ myślę, że radzą sobie z wszystkim, czego potrzebuję. Dodaj własne schematy kodowania do funkcji demo i przetestuj własne dane wejściowe.
Jeszcze jedno: w systemie Windows jest trudne zadanie: apparently crazy application developers.
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import os
import sys
def encodingDemo(str):
validStrings =()
try:
print "str =",str,"{0} repr(str) = {1}".format(type(str), repr(str))
validStrings += ((str,""),)
except UnicodeEncodeError as ude:
print "Couldn't print the str itself because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print ude
try:
x = unicode(str)
print "unicode(str) = ",x
validStrings+= ((x, " decoded into unicode by the default system encoding"),)
except UnicodeDecodeError as ude:
print "ERROR. unicode(str) couldn't decode the string because the system encoding is set to an encoding that doesn't understand some character in the string."
print "\tThe system encoding is set to {0}. See error:\n\t".format(sys.getdefaultencoding()),
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the unicode(str) because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print uee
try:
x = str.decode('latin_1')
print "str.decode('latin_1') =",x
validStrings+= ((x, " decoded with latin_1 into unicode"),)
try:
print "str.decode('latin_1').encode('utf_8') =",str.decode('latin_1').encode('utf_8')
validStrings+= ((x, " decoded with latin_1 into unicode and encoded into utf_8"),)
except UnicodeDecodeError as ude:
print "The string was decoded into unicode using the latin_1 encoding, but couldn't be encoded into utf_8. See error:\n\t",
print ude
except UnicodeDecodeError as ude:
print "Something didn't work, probably because the string wasn't latin_1 encoded. See error:\n\t",
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the str.decode('latin_1') because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print uee
try:
x = str.decode('utf_8')
print "str.decode('utf_8') =",x
validStrings+= ((x, " decoded with utf_8 into unicode"),)
try:
print "str.decode('utf_8').encode('latin_1') =",str.decode('utf_8').encode('latin_1')
except UnicodeDecodeError as ude:
print "str.decode('utf_8').encode('latin_1') didn't work. The string was decoded into unicode using the utf_8 encoding, but couldn't be encoded into latin_1. See error:\n\t",
validStrings+= ((x, " decoded with utf_8 into unicode and encoded into latin_1"),)
print ude
except UnicodeDecodeError as ude:
print "str.decode('utf_8') didn't work, probably because the string wasn't utf_8 encoded. See error:\n\t",
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the str.decode('utf_8') because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",uee
print
print "Printing information about each character in the original string."
for char in str:
try:
print "\t'" + char + "' = original char {0} repr(char)={1}".format(type(char), repr(char))
except UnicodeDecodeError as ude:
print "\t'?' = original char {0} repr(char)={1} ERROR PRINTING: {2}".format(type(char), repr(char), ude)
except UnicodeEncodeError as uee:
print "\t'?' = original char {0} repr(char)={1} ERROR PRINTING: {2}".format(type(char), repr(char), uee)
print uee
try:
x = unicode(char)
print "\t'" + x + "' = unicode(char) {1} repr(unicode(char))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = unicode(char) ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = unicode(char) {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
try:
x = char.decode('latin_1')
print "\t'" + x + "' = char.decode('latin_1') {1} repr(char.decode('latin_1'))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = char.decode('latin_1') ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = char.decode('latin_1') {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
try:
x = char.decode('utf_8')
print "\t'" + x + "' = char.decode('utf_8') {1} repr(char.decode('utf_8'))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = char.decode('utf_8') ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = char.decode('utf_8') {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
print
x = 'ó'
encodingDemo(x)
Bardzo dziękuję za odpowiedzi poniżej, a szczególnie za @Johna Machina za udzielenie odpowiedzi tak dokładnie.
miałem moją konfigurację terminala na latin1, więc zmienia. Kiedy pytasz, co nazywam ciągami Unicode, użyłem metody unicode() na str, z której czytałem. Nie rozumiałem, że znaki unicode nadal zawierają niejawne kodowanie. Czy mówię to tak? Wygląda na to, że kod unicode ("\ xF3") i "\ xF3" .decode ("latin1") są takie same, gdy zostały obliczone za pomocą funkcji repr(). Czy to jest szczęśliwa okoliczność, czy też unicode ("str") zawsze zwróci poprawne dekodowanie? Jeśli nie, to kiedy otrzymam pytona, który ma ustawiony dowolny zestaw znaków, skąd mam wiedzieć, jak to rozszyfrować? –
Jeszcze raz dziękuję. Domyślam się, że odpowiedź na twoje pytanie "Co nazywasz ciągami Unicode? UTF-16?" jest "czymkolwiek jest Oacute_unicode". Czy brakuje mi jakiegoś aspektu twojego pytania, które powinienem zrozumieć? Dekodowałem ciągi znaków otrzymane z nazw plików i wysyłałem je do bazy danych w tej formie. Zamówiłem też dziesięć z tamburynem Pentagonu, więc wkrótce będę miał możliwości dekodowania wojskowego, a python będzie niepotrzebny. –
Właśnie sprawdzałem, czy naprawdę chodzi o obiekty unicode Pythona == czym jest Oacute_unicode, a nie o UTF-16, które jest inną możliwością kodowania w bazach SQLite i które niektórzy nazywają "Unicode". –