Discussion:
python, mysql og unicode
(for gammel til at besvare)
Anders Wegge Keller
2008-11-17 14:07:34 UTC
Permalink
Jeg har en stribe URL-encodede strenge, som jeg skal have puttet i en
mysql-database. Det går fint nok med f. eks

urllib.unquote('%C3%85rhus').decode('utf-8)

der giver mig en nydelig unicodestreng der står Århus i. Den er lige
til at sætte i databasen. Men når man så kommer til de mere eksotiske
strenge som f. eks '%C5%81%C3%B3d%C5%BA', får jeg en exception:

UnicodeEncodeError: 'latin-1' codec can't encode character
u'\u0141' in position 46: ordinal not in range(256)

Det undrer mig en smule, da jeg i mit MySQLdb.connect() har
use_unicode=True. Jeg kan ikke helt gennemskue om det er fordi min
oprindelige streng ikke er valid utf-8, eller om det slet og ret er
fordi MySQLdb hårdnakket ænsker at oversætte til 8859-1.

Er der nogen der kan komme med et bud på hvordan jg i det mindste får
afgrænset problemet til den ene af de to muligheder?

PS. Til dem der måtte undre sig, kan jeg fortælle at der er tale om
navnet på den trediestørste by i Polen.
--
/Wegge
Klaus Alexander Seistrup
2008-11-17 14:46:10 UTC
Permalink
[...] når man så kommer til de mere eksotiske strenge som
UnicodeEncodeError: 'latin-1' codec can't encode character
u'\u0141' in position 46: ordinal not in range(256)
Jeg har ingen problemer med '%C5%81%C3%B3d%C5%BA':

#v-

import urllib, unicodedata

for c in unicode(urllib.unquote('%C5%81%C3%B3d%C5%BA'), 'utf-8'):
print unicodedata.name(c)

LATIN CAPITAL LETTER L WITH STROKE
LATIN SMALL LETTER O WITH ACUTE
LATIN SMALL LETTER D
LATIN SMALL LETTER Z WITH ACUTE

#v-

Det er måske værd at notere sig at din fejlmeddelelse siger at
»'latin-1' codec can't encode«, så der er noget der kan tyde på at
noget i koden forventer input i Latin-1.

Hvis du bruger

streng = unicode(urllib.unquote('%C5%81%C3%B3d%C5%BA'), 'utf-8').encode('utf-8')

får du så samme fejlmeddelelse?

Måske kan problemet løses ved noget så simpelt som at putte

# -*- coding: utf-8 -*-

som første eller anden linje i koden (PEP-0263):

· http://www.python.org/dev/peps/pep-0263/

Mvh,
--
Klaus Alexander Seistrup
http://klaus.seistrup.dk/
Anders Wegge Keller
2008-11-17 18:30:51 UTC
Permalink
Post by Klaus Alexander Seistrup
Det er måske værd at notere sig at din fejlmeddelelse siger at
»'latin-1' codec can't encode«, så der er noget der kan tyde på at
noget i koden forventer input i Latin-1.
Ja, det er åbenbart connectoren der ikke vil være med til at fylde
utf i et felt der er defineret som TEXT :(
Post by Klaus Alexander Seistrup
Måske kan problemet løses ved noget så simpelt som at putte
# -*- coding: utf-8 -*-
Den er med som default, men det var da et godt bud.

Jeg tror som sagt jeg har fået redefineret mit problem, men du skal
have tak for den tid du brugte på at svare.
--
/Wegge
Anders J. Munch
2008-11-17 18:04:42 UTC
Permalink
Post by Anders Wegge Keller
Jeg har en stribe URL-encodede strenge, som jeg skal have puttet i en
mysql-database. Det går fint nok med f. eks
urllib.unquote('%C3%85rhus').decode('utf-8)
der giver mig en nydelig unicodestreng der står Århus i. Den er lige
til at sætte i databasen. Men når man så kommer til de mere eksotiske
UnicodeEncodeError: 'latin-1' codec can't encode character
u'\u0141' in position 46: ordinal not in range(256)
Det undrer mig en smule, da jeg i mit MySQLdb.connect() har
use_unicode=True. Jeg kan ikke helt gennemskue om det er fordi min
oprindelige streng ikke er valid utf-8, eller om det slet og ret er
fordi MySQLdb hårdnakket ænsker at oversætte til 8859-1.
Det sidste. Hvis strengen ikke havde været utf-8, så ville du have fået en
Unicode/De/codeError i stedet.

Mon ikke nogen har glemt at kigge på CHARACTER SET parameteren, da databasen
blev oprettet?

mvh. Anders
Anders Wegge Keller
2008-11-17 18:27:55 UTC
Permalink
Post by Anders J. Munch
Post by Anders Wegge Keller
UnicodeEncodeError: 'latin-1' codec can't encode character
u'\u0141' in position 46: ordinal not in range(256)
Mon ikke nogen har glemt at kigge på CHARACTER SET parameteren, da
databasen blev oprettet?
Nogen er mig, og jeg har slet ikke sat den til noget. MySQL er
ophøjet ligeglad med hvad man stopper i en TEXT-type, så jeg er lidt
overrasket over at connectoren pludselig synes den skal blande sig.

Så nu er spørgsmålet åbenbart ændret til hvad der findes af
DB-abstraktioner, der ikke snager i de data de flytter rundt på.
--
/Wegge
Anders J. Munch
2008-11-17 20:17:52 UTC
Permalink
Post by Anders Wegge Keller
Post by Anders J. Munch
Mon ikke nogen har glemt at kigge på CHARACTER SET parameteren, da
databasen blev oprettet?
Nogen er mig, og jeg har slet ikke sat den til noget. MySQL er
ophøjet ligeglad med hvad man stopper i en TEXT-type, så jeg er lidt
overrasket over at connectoren pludselig synes den skal blande sig.
Når du ikke har valgt tegnsæt, så har MySQL bare givet dig en default. Den
default er åbenbart latin-1. Prøv med en SHOW CREATE DATABASE og se.
Post by Anders Wegge Keller
Så nu er spørgsmålet åbenbart ændret til hvad der findes af
DB-abstraktioner, der ikke snager i de data de flytter rundt på.
Jamen så brug da en BLOB, hvis det er det du vil have. TEXT har nu engang et
defineret tegnsæt.

Du kan måske snyde MySQLdb ved at give den en allerede indkodet streng i st. for
unicode. Altså .encode('utf-8'). Men bliv så ikke overrasket hvis din næste
SELECT giver mojibake.

mvh. Anders
Anders Wegge Keller
2008-11-17 20:50:03 UTC
Permalink
Post by Anders J. Munch
Når du ikke har valgt tegnsæt, så har MySQL bare givet dig en
default. Den default er åbenbart latin-1. Prøv med en SHOW CREATE
DATABASE og se.
Det er jeg udmærket klar over. Men det ændrer ikke på at jeg har lyst
til at putte UTF-8 i mine textfelter.
Post by Anders J. Munch
Jamen så brug da en BLOB, hvis det er det du vil have. TEXT har nu
engang et defineret tegnsæt.
Jeg skal bruge en TEXT, fordi det er det tabellen jeg i sidste ende
skal til at manipulere på er en MEDIUMTEXT. Og den står ikke til at
ændre, ligesom den implementation der bruger databasen nu har det
rigtig fint med at stoppe utf-8 i en database der er oprettet som
latin-1.
Post by Anders J. Munch
Du kan måske snyde MySQLdb ved at give den en allerede indkodet
streng i st. for unicode. Altså .encode('utf-8'). Men bliv så ikke
overrasket hvis din næste SELECT giver mojibake.
Så vil jeg hellere finde mig et abstraktionslag der ikke blander sig.
--
/Wegge
Anders J. Munch
2008-11-17 22:38:51 UTC
Permalink
Post by Anders Wegge Keller
Jeg skal bruge en TEXT, fordi det er det tabellen jeg i sidste ende
skal til at manipulere på er en MEDIUMTEXT. Og den står ikke til at
ændre [...]
Du har undersøgt mulighederne for at ændre tegnsætserklæringerne med alter table?
Post by Anders Wegge Keller
Så vil jeg hellere finde mig et abstraktionslag der ikke blander sig.
Det er vel bare use_unicode=False?

- Anders
Anders Wegge Keller
2008-11-18 09:47:49 UTC
Permalink
Post by Anders J. Munch
Post by Anders Wegge Keller
Jeg skal bruge en TEXT, fordi det er det tabellen jeg i sidste ende
skal til at manipulere på er en MEDIUMTEXT. Og den står ikke til at
ændre [...]
Du har undersøgt mulighederne for at ændre tegnsætserklæringerne med alter table?
Det ville næppe være befordrende for min wikis fortsatte stabilitet.
Post by Anders J. Munch
Post by Anders Wegge Keller
Så vil jeg hellere finde mig et abstraktionslag der ikke blander sig.
Det er vel bare use_unicode=False?
Ja, det var selvfølgelig en mulighed at lave encode og decode på den
side af hegnet.
--
/Wegge
Loading...