2010-08-15 30 views
7

así que tengo esta página:¿Cómo puedo verificar una cadena Unicode de Python para ver que * en realidad * es Unicode correcto?

http://hub.iis.sinica.edu.tw/cytoHubba/

Al parecer es todo tipo de mal estado, ya que se decodifica correctamente, pero cuando trato de guardarlo en postgres me sale:

DatabaseError: invalid byte sequence for encoding "UTF8": 0xedbdbf 

El la base de datos se bloquea después de eso y se niega a hacer nada sin una reversión, que será un poco difícil de publicar (larga historia). ¿Hay alguna forma de que compruebe si esto sucederá antes de que llegue a la base de datos? source.encode ("utf-8") funciona sin problemas, por lo que no estoy seguro de lo que está pasando ...

+0

¿Está seguro de que su conexión está configurada para usar UTF-8? – Wolph

+0

Sí, 300,000 páginas web adicionales se agregaron muy bien, es solo esta que falla ... –

Respuesta

9

Hay un error en python 2.x que solo se ha arreglado en python 3.x. De hecho, este error es incluso en iconv de OS X (pero no en glibc).

Esto es lo que está pasando:

Python 2.x no reconoce pares UTF8 sustitutas [1] como siendo válido (que es lo que su secuencia de caracteres es)

Este debe ser todo lo que se necesita:

foo.decode('utf8').encode('utf8') 

pero gracias a ese insecto que están no está arreglando, no atrapa parejas sustitutas.

Prueba esto en Python 2.x y luego en 3.x:

b'\xed\xbd\xbf'.decode('utf8') 

Se generará un error (correctamente) en el segundo. Tampoco lo están arreglando en la rama 2.x. Véase [2] y [3] para más información

[1] http://tools.ietf.org/html/rfc3629#section-4

[2] http://bugs.python.org/issue9133

[3] http://bugs.python.org/issue8271#msg102209

+0

Gracias, esto es lo que sospechaba. Elegido como correcto. –

+0

No hay problema. Intentaba hacer más o menos lo que estabas haciendo para filtrar mis datos al hacer una COPIA en postgres. Lo que terminé haciendo fue dejar que fallara y filtrar filas individuales en función de las salidas de error. Se basaba en la idea general de cómo funciona el código de copiado en pgloader http://pgfoundry.org/projects/pgloader/ – mikelikespie

+0

no relacionado: si desea reparar los pares de sustitución: 'u '[\ ud83d \ ude42]'. codificar ('utf-16', 'surrogatepass'). decode ('utf-16') = u '[\ U0001f642]' ' – jfs

1

Un objeto Python unicode es una secuencia de puntos de código Unicode y por definición propio unicode. Una cadena de python str es una secuencia de bytes que pueden ser caracteres Unicode codificados con cierta codificación (UTF-8, Latin-1, Big5, ...).

La primera pregunta es si source es un objeto unicode o una cadena str. Ese source.encode("utf-8") funciona solo significa que puede convertir source en una cadena codificada en UTF-8, pero ¿lo está haciendo antes de pasarlo a la función de base de datos? La base de datos parece esperar que sus entradas se codifiquen con UTF-8, y se queja de que el equivalente de source.decode("utf-8") falla.

Si source es un objeto unicode, debe estar codificado en UTF-8 antes de pasarlo a la base de datos:

source = u'abc' 
call_db(source.encode('utf-8')) 

Si source es una str codificado como otra cosa que no sea UTF-8, que debiera decodificar esa codificación y luego codificar el objeto Unicode resultante a UTF-8:

source = 'abc' 
call_db(source.decode('Big5').encode('utf-8')) 
+1

Lo siento, debería haber aclarado. source es un objeto unicode que se codifica bien en Python, las cosas se rompen cuando intento enviarlo a postgres ... –

0

¿Qué estás haciendo exactamente? El contenido en efecto, decodificar bien como utf-8:

>>> import urllib 
>>> webcontent = urllib.urlopen("http://hub.iis.sinica.edu.tw/cytoHubba/").read() 
>>> unicodecontent = webcontent.decode("utf-8") 
>>> type(webcontent) 
<type 'str'> 
>>> type(unicodecontent) 
<type 'unicode'> 
>>> type(unicodecontent.encode("utf-8")) 
<type 'str'> 

asegurarse de que entiende la diferencia entre cadenas Unicode y UTF-8 cadenas codificadas, sin embargo. Lo que necesita enviar a la base de datos es unicodecontent.encode("utf-8") (que es lo mismo que webcontent, pero decodificó para verificar que no tenga tenga secuencias de bytes no válidas en su fuente).

De hecho, como WoLpH dice, compruebe la configuración de la base de datos y la conexión a la base de datos.

+0

Estoy usando Django, que codifica todo correctamente, pero es postgres que decide que la codificación (o cadena codificada) es malo, por alguna razón ... Todo lo que hago en Python funciona, es por eso que no puedo detectarlo. Tal vez es un error postgres? –

0

Al final, opté por solucionar este problema, detectar el error y deshacer la transacción utilizando la administración de transacciones de Django. Estoy desconcertado de por qué ocurriría, aunque ...

0

Para resolver mis problemas similares con django/Postgress ahora haga algo como esto

class SafeTextField(models.TextField) 
    def get_prep_value(self, value): 
     encoded = base64.encodestring(value).strip() 
     return super(SafeTextField, self).get_prep_value(encoded) 
    def to_python(self, value): 
     decoded = base64.decodestring(value) 
     return super(SafeTextField, self).to_python(decoded) 
Cuestiones relacionadas