Domanda

Ho iniziato cercando di memorizzare le stringhe in sqlite usando python, e ha capito il messaggio:

sqlite3.ProgrammingError:Si deve non usare 8 bit bytestrings a meno che non si utilizzare un text_factory grado di interpretare 8-bit bytestrings (come text_factory = str).E ' altamente raccomandato che tu, invece, basta passare il vostro applicazione di stringhe Unicode.

Ok, ho acceso le stringhe Unicode.Poi ho iniziato a ricevere il messaggio:

sqlite3.OperationalError:Non poteva per la decodifica a UTF-8 colonna 'tag_artist' con il testo 'Sigur Rós'

quando si tenta di recuperare i dati dal db.Ulteriori ricerche e ho iniziato la codifica in utf-8, ma poi e 'Sigur Rós' inizia a cercare come 'Sigur RÃ3s'

nota: La mia console è stata impostata per la visualizzazione in 'latin_1' come @John Machin ha sottolineato.

Che cosa dà?Dopo la lettura questo, descrivendo esattamente la stessa situazione in cui mi trovo, sembra come se il consiglio è di ignorare l'altro la consulenza e l'utilizzo di 8 bit bytestrings, dopo tutto.

Non sapevo molto su unicode e utf prima di iniziare questo processo.Ho imparato un bel po ' negli ultimi paio d'ore, ma io sono ancora ignorante se c'è un modo per convertire correttamente 'ó' dal latin-1 a utf-8 e non mangle di esso.Se non c'è, perché sqlite 'vivamente' posso passare la mia applicazione per le stringhe unicode?


Ho intenzione di aggiornare a questa domanda con una sintesi e il codice di esempio di tutto quello che ho imparato nelle ultime 24 ore, in modo che qualcuno nelle mie scarpe può avere un facile(er) guida.Se le informazioni di cui ho post è sbagliato o fuorviante, in qualsiasi modo, la prego di dirmi e ti aggiorna, o uno di voi senior ragazzi possono aggiornare.


Sintesi delle risposte

Permettetemi innanzitutto di stato l'obiettivo, da quanto ho capito.L'obiettivo nel trattamento di varie codifiche, se si sta tentando di convertire tra di loro, è quello di capire che cosa la vostra fonte di codifica è, poi convertire unicode utilizzando che codifica della sorgente, poi convertire il vostro codifica desiderata.Unicode è un base e codifiche sono mappature di sottoinsiemi di base.utf_8 è dotato di camere per ogni carattere unicode, ma perché non sono nello stesso luogo, come, per esempio, latin_1, una stringa codificata in utf_8 e inviato a un latin_1 console non ha l'aspetto desiderato.In python il processo di arrivare a unicode e in un'altra codifica, assomiglia a questo:

str.decode('source_encoding').encode('desired_encoding')

o se la str è già in unicode

str.encode('desired_encoding')

Per sqlite realtà non volevo codificare di nuovo, volevo decodificare e lasciare in formato unicode.Qui ci sono quattro cose che si potrebbe aver bisogno di essere consapevoli di come si tenta di lavorare con unicode e codifiche in python.

  1. La codifica della stringa che si desidera lavorare con, e la codifica che si desidera ottenere.
  2. Il sistema di codifica.
  3. La console di codifica.
  4. La codifica del file di origine

Elaborazione:

(1) Quando si legge una stringa da una fonte, deve avere qualche tipo di codifica, come latin_1 o utf_8.Nel mio caso, io sono sempre stringhe da nomi di file, così, purtroppo, non ho potuto ottenere qualsiasi tipo di codifica.Windows XP utilizza UCS-2 (un sistema Unicode) come il suo nativo di tipo stringa, che sembra come barare a me.Fortunatamente per me, i personaggi più nomi di file non sono andando essere fatto di più di una sorgente tipo di codifica, e penso che tutti i miei erano completamente latin_1, completamente utf_8, o semplicemente ascii (che è un sottoinsieme di quelli).Così ho appena leggere e decodificato come se fossero ancora in latin_1 o utf_8.È possibile, però, che si potrebbe avere latin_1 e utf_8 e quant'altri personaggi mescolati insieme in un nome di file su Windows.A volte quei personaggi in grado di visualizzare fino scatole, altre volte sembrano alterati, e altre volte sembrano corrette (caratteri accentati e quant'altro).Di passare.

(2) Python ha un sistema predefinito di codifica che viene impostata quando python inizia e non può essere modificato durante l'esecuzione.Vedere qui per ulteriori dettagli.Sporco riepilogo ...bene, ecco il file che ho aggiunto:

\# 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')  

Questo sistema di codifica è quella che viene utilizzato quando si utilizzano unicode("str") funzione senza altri parametri di codifica.Per dire che un altro modo, python tenta di decodificare "str" unicode in base all'impostazione predefinita del sistema di codifica.

(3) Se si utilizza INATTIVITÀ o la riga di comando python, credo che le console vengono visualizzati in base all'impostazione predefinita del sistema di codifica.Sto usando pydev con eclipse per qualche motivo, così ho dovuto andare nel mio progetto di impostazioni, modificare la configurazione di lancio proprietà di mio script di test, vai alla scheda Comune e modificare la console da latin-1 a utf-8 in modo che io possa confermare quello che mi stava facendo stava lavorando.

(4) Se si vuole avere un po ' di test stringhe, ad esempio,

test_str = "ó"

nel codice sorgente, quindi si dovrà dire a python che tipo di codifica in uso in quel file.(FYI:quando ho digitato in modo errato una codifica ho dovuto ctrl-Z, perché il mio file è diventato illeggibile.) Questo è facilmente realizzabile mettendo una linea così in alto del tuo file di codice sorgente:

# -*- coding: utf_8 -*-

Se non si dispone di queste informazioni, python tenta di analizzare il codice ascii per impostazione predefinita, e quindi:

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

Una volta che il programma funzioni correttamente, o, se non si utilizza python console o qualsiasi altra console per guardare uscita, è probabile che davvero si preoccupano solo #1 sulla lista.Di default del sistema e console di codifica non è importante a meno che non hai bisogno di guardare in uscita e/o in uso builtin unicode() funzione (senza parametri di codifica) al posto della stringa.decode() funzione.Ho scritto una funzione demo mi si incolla in fondo di questo gigantesco pasticcio che spero dimostra correttamente le voci nella mia lista.Ecco alcuni degli output quando eseguo il carattere 'ó' attraverso la funzione demo, che mostra come i vari metodi di reagire al carattere di input.Il mio sistema di codifica e di uscita della console sono entrambi utf_8 per questa esecuzione:

'�' = 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

Ora voglio cambiare il sistema e console di codifica latin_1, e ottengo questo a parità di input:

'ó' = 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

Si noti che l '"originale" il carattere viene visualizzato correttamente e builtin unicode() funziona ora.

Ora devo modificare la mia console di output di nuovo 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

Qui tutto funziona ancora lo stesso come l'ultima volta, ma la console non è possibile visualizzare l'output corretto.Ecc.La funzione riportata di seguito, inoltre, visualizza ulteriori informazioni che questo e speriamo che vorresti aiutare qualcuno a capire dove il divario nella loro comprensione.So che tutte queste informazioni sono, in altri luoghi e più approfonditamente affrontato, ma mi auguro che questo sarebbe un buon inizio punto per qualcuno che cerca di ottenere la codifica con python e/o sqlite.Le idee sono grandi, ma a volte il codice sorgente può risparmiare un giorno o due, cercando di capire quali funzioni fare cosa.

Disclaimers:Io non sono un esperto di codifica, ho messo insieme per aiutare la mia comprensione.Ho continuato a costruire su di esso quando avrei iniziato probabilmente il passaggio di funzioni come argomenti di evitare tante codice ridondante, quindi se posso farò più concisa.Inoltre, utf_8 e latin_1 non sono il solo schemi di codifica, sono solo le due sono stato a giocare con perché penso che gestire tutto ciò di cui ho bisogno.Aggiungere i propri schemi di codifica per la funzione demo e testare il proprio ingresso.

Ancora una cosa:ci sono apparentemente folle gli sviluppatori di applicazioni rendendo la vita difficile in Windows.

#!/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)

Vi ringrazio molto per le risposte e soprattutto a @John Machin per rispondere così a fondo.

È stato utile?

Soluzione

Io sono ancora ignorante se c'è un modo per convertire correttamente 'ó' dal latin-1 a utf-8 e non mangle è

repr() e unicodedata.nome() sono i tuoi amici quando si tratta di debug di questi problemi:

>>> oacute_latin1 = "\xF3"
>>> oacute_unicode = oacute_latin1.decode('latin1')
>>> oacute_utf8 = oacute_unicode.encode('utf8')
>>> print repr(oacute_latin1)
'\xf3'
>>> print repr(oacute_unicode)
u'\xf3'
>>> import unicodedata
>>> unicodedata.name(oacute_unicode)
'LATIN SMALL LETTER O WITH ACUTE'
>>> print repr(oacute_utf8)
'\xc3\xb3'
>>>

Se si invia oacute_utf8 per un terminale che è impostato per latin1, si otterrà la tilde seguita da apice-3.

Ho acceso le stringhe Unicode.

Quali sono chiamate le stringhe Unicode?UTF-16?

Che cosa dà?Dopo la lettura di questo, che descrive esattamente la stessa situazione in cui mi trovo, sembra come se il consiglio è di ignorare l'altro la consulenza e l'utilizzo di 8 bit bytestrings, dopo tutto.

Non riesco a immaginare come sembra anche a voi.La storia che è stato trasportato era che unicode oggetti in Python e la codifica UTF-8 nel database sono il modo di andare.Tuttavia Martin risposto alla domanda originale, dando un metodo ("testo di fabbrica") per il por di essere in grado di utilizzare latin1 -- questo NON costituisce una raccomandazione!

Aggiornamento in risposta a queste ulteriori domande in un commento:

Non ho capito che i caratteri unicode ancora contenute, un implicito di codifica.Sto dicendo che a destra?

No.La codifica è un mapping tra Unicode e qualcos'altro, e viceversa.Un carattere Unicode non hanno una codifica, implicita o esplicita.

A me sembra unicode("\xF3") e "\xF3".decode('latin1') sono le stesse di quando valutate con repr().

Dire che cosa?Non assomiglia a me:

>>> unicode("\xF3")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf3 in position 0: ordinal
not in range(128)
>>> "\xF3".decode('latin1')
u'\xf3'
>>>

Forse volevi dire: u'\xf3' == '\xF3'.decode('latin1') ...questo è certamente vero.

È anche vero che unicode(str_object, encoding) fa la stessa cosa str_object.decode(encoding) ...tra esplodere quando un inappropriato di codifica è in dotazione.

È che una felice circostanza

Che i primi 256 caratteri in Unicode sono le stesse, codice per codice, come i 256 caratteri latin1 è una buona idea.Perché tutti i possibili 256 caratteri latin1 vengono mappati a Unicode, significa che QUALSIASI byte a 8 bit, QUALSIASI Python str oggetto può essere codificato in unicode, senza essere un'eccezione sollevata.Questo è come dovrebbe essere.

Tuttavia ci sono alcune persone che confondere due concetti separati:"il mio script viene eseguito fino al completamento, senza eccezioni sollevate" e "il mio script è esente da errori".Per loro, latin1 è "una trappola e un delirio".

In altre parole, se si dispone di un file che in realtà è codificato in cp1252 o vb o koi8-u o qualsiasi altra cosa e si decodifica utilizzando latin1, risultante Unicode sarà totale dei rifiuti e Python (o qualsiasi altra lingua) non di bandiera un errore-non ha alcun modo di sapere che avete commesso una sciocchezza.

o è unicode("str") andando sempre restituire la corretta decodifica?

In questo modo, con la codifica di default in fase di ascii, verrà restituito l'unicode corretto se il file è effettivamente codificato in ASCII.In caso contrario, verrà blow up.

Allo stesso modo, se si specifica la codifica corretta, o uno che è un superset di codifica corretta, si otterrà il risultato corretto.Altrimenti si otterrà una serie di caratteri incomprensibili o di un'eccezione.

In breve:la risposta è no.

Se non, quando ricevo un pitone str che ha ogni possibile set di caratteri in esso, come faccio a sapere come decodificarlo?

Se la str oggetto di un documento XML valido, sarà specificato di fronte.Di Default è UTF-8.Se costruito correttamente la pagina web, deve essere specificato anteriore (cerca "set di caratteri").Purtroppo molti scrittori di pagine web si trovano tra i denti (ISO-8859-1 aka latin1, dovrebbe essere Windows-1252 aka cp1252;non sprecare risorse, nel tentativo di decifrare gb2312, utilizzare vb, invece).È possibile ottenere degli indizi che la nazionalità, la lingua del sito.

UTF-8 è sempre la pena di provare.Se i dati ascii, funzionerà bene, perché ascii è un sottoinsieme di utf8.Una stringa di testo che è stato scritto utilizzando caratteri non-ascii ed è stato codificato in una diversa codifica utf8 quasi certamente non con un'eccezione se si tenta di decodificare, come utf8.

Tutto quanto sopra euristica e di più e un sacco di statistiche sono incapsulati in chardet, un modulo per indovinare la codifica di file arbitrari.Di solito funziona bene.Tuttavia non è possibile realizzare un software a prova di idiota.Per esempio, se è possibile concatenare i file di dati scritti alcuni con codifica A e alcune con codifica B, e inserire i risultati per chardet, la risposta è probabilmente la codifica C con un ridotto livello di fiducia ad es.0.8.Controllare sempre la fiducia di una parte della risposta.

Se tutto il resto fallisce:

(1) Prova a chiedere qui, con un piccolo campione dal fronte dei dati ... print repr(your_data[:400]) ...e qualunque garanzia informazioni sulla sua provenienza che si hanno.

(2) i Recenti russo di ricerca in tecniche per il recupero di password dimenticate sembra essere abbastanza applicabile a dedurre unknown codifiche.

Aggiorna 2 BTW, non è ora che hai aperto un'altra domanda ?-)

Ancora una cosa:a quanto pare ci sono personaggi che Windows utilizza come Unicode per alcuni caratteri che non sono l'Unicode corretto per quel tipo di personaggio, così si può avere la mappa di quei personaggi, quelle corrette se si desidera utilizzare altri programmi che sono in attesa di questi caratteri nel posto giusto.

Non è Windows che si sta facendo;si tratta di una manciata di pazzi gli sviluppatori di applicazioni.Si potrebbe avere più comprensibilmente non parafrasato, ma ha citato il paragrafo di apertura del effbot articolo a cui si fa riferimento:

Alcune applicazioni aggiungere CP1252 (Windows, Europa Occidentale) caratteri per i documenti contrassegnati come ISO 8859-1 (Latin 1) o altre codifiche.Questi caratteri non sono validi ISO-8859-1 caratteri, e può causare tutti i tipi di problemi di elaborazione e le applicazioni di visualizzazione.

Sfondo:

La gamma U+0000 a U+001F inclusive è designato in Unicode come "C0 Caratteri di Controllo".Questi esistono anche in formato ASCII e latin1, con gli stessi significati.Essi comprendono come il mattone di cose come carriage return, line feed, campana, backspace, tab, e altri che vengono utilizzati raramente.

La gamma U+0080 U+009F inclusive è designato in Unicode come "C1 Caratteri di Controllo".Questi esistono anche in latin1, e sono a 32 caratteri che nessuno, al di fuori unicode.org può immaginare qualsiasi possibile utilizzare per.

Di conseguenza, se si esegue un personaggio frequenza contare sul vostro unicode o latin1 dati, e la ricerca di eventuali caratteri nell'intervallo, i tuoi dati sono danneggiati.Non esiste una soluzione universale;dipende da come è stato danneggiato.I personaggi può hanno lo stesso significato di cp1252 personaggi nelle stesse posizioni, e quindi la effbot della soluzione di lavoro.In un altro caso che ho cercato di recente, il dodgy personaggi sembrano essere stati causati dalla concatenazione di file di testo codificato in UTF-8 e un altro di codifica che ha bisogno di essere ricavati dalla lettera di frequenze (umana) lingua i file sono stati scritti in.

Altri suggerimenti

UTF-8 è la codifica di default del database SQLite.Questo si manifesta in situazioni come "SELECT CAST(x'52C3B373' COME TESTO);".Tuttavia, SQLite libreria C, che in realtà non verificare se una stringa inserita nel DB è valido UTF-8.

Se si inserisce un Pitone unicode oggetto (o str oggetto in 3.x), Python sqlite3 libreria la converte automaticamente in UTF-8.Ma se si inserisce una str oggetto, sarà solo assumere la stringa è UTF-8, perché Python 2.x "str" non conosce la sua codifica.Questo è un motivo per preferire le stringhe Unicode.

Tuttavia, non ti aiuta se i dati è rotto per iniziare con.

Per risolvere i tuoi dati, fare

db.create_function('FIXENCODING', 1, lambda s: str(s).decode('latin-1'))
db.execute("UPDATE TheTable SET TextColumn=FIXENCODING(CAST(TextColumn AS BLOB))")

per ogni colonna di testo nel database.

Ho risolto pysqlite problema impostando:

conn.text_factory = lambda x: unicode(x, 'utf-8', 'ignore')

Per impostazione predefinita text_factory è impostato su unicode(), che consentirà di utilizzare la corrente di default la codifica ascii (sulla mia macchina)

Naturalmente non c'è.Ma i dati sono già rotto nel database, in modo da avrete bisogno di risolvere il problema:

>>> print u'Sigur Rós'.encode('latin-1').decode('utf-8')
Sigur Rós

Il mio unicode problemi con Python 2.x (Python 2.7.6 per essere precisi) ha risolto questo:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

Ha anche risolto l'errore di cui parli all'inizio del post:

sqlite3.ProgrammingError:Non si deve usare 8 bit bytestrings a meno che non ...

MODIFICA

sys.setdefaultencoding è un sporco hack.Sì, è possibile risolvere UTF-8 problemi, ma tutto ha un prezzo.Per ulteriori dettagli, fare riferimento al seguente link:

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top