Advertencia generada al insertar unicode de 4 bytes en mysql

Mira lo siguiente:

/home/kinka/workspace/py/tutorial/tutorial/pipelines.py:33: Warning: Incorrect string value: '\xF0\x9F\x91\x8A\xF0\x9F...' for column 't_content' at row 1 n = self.cursor.execute(self.sql, (item['topic'], item['url'], item['content'])) 

La cadena '\xF0\x9F\x91\x8A , en realidad es un '\xF0\x9F\x91\x8A Unicode de 4 bytes: u'\U0001f62a' . El conjunto de caracteres de mysql es utf-8, pero al insertar unicode de 4 bytes, truncará la cadena insertada. Busqué en Google este problema y descubrí que mysql bajo 5.5.3 no es compatible con Unicode de 4 bytes, y desafortunadamente el mío es 5.5.224. No quiero actualizar el servidor mysql, así que solo quiero filtrar el código Unicode de 4 bytes en Python. Intenté usar una expresión regular pero fallé. Entonces, ¿alguna ayuda?

Si MySQL no puede manejar códigos UTF-8 de 4 bytes o más, tendrá que filtrar todos los caracteres Unicode sobre el punto de código \U00010000 ; UTF-8 codifica puntos de código por debajo de ese umbral en 3 bytes o menos.

Podrías usar una expresión regular para eso:

 >>> import re >>> highpoints = re.compile(u'[\U00010000-\U0010ffff]') >>> example = u'Some example text with a sleepy face: \U0001f62a' >>> highpoints.sub(u'', example) u'Some example text with a sleepy face: ' 

Alternativamente, puede usar la función .translate() con una tabla de mapeo que solo contiene valores None :

 >>> nohigh = { i: None for i in xrange(0x10000, 0x110000) } >>> example.translate(nohigh) u'Some example text with a sleepy face: ' 

Sin embargo, crear la tabla de traducción consumirá mucha memoria y tomará algún tiempo para generarla; Probablemente no valga la pena su esfuerzo, ya que el enfoque de expresión regular es más eficiente.

Todo esto supone que estás usando un python comstackdo UCS-4. Si su Python fue comstackdo con soporte UCS-2, solo puede usar puntos de código hasta '\U0000ffff' en expresiones regulares y nunca se encontrará con este problema en primer lugar.

Observo que a partir de MySQL 5.5.3 el códec utf8mb4 recién agregado admite el rango completo de Unicode.

Creo que deberías usar utf8mb4 colation en lugar de utf8 y ejecutar

 SET NAMES UTF8MB4 

después de la conexión con DB ( enlace , enlace , enlace )

Simple normalización para cadena sin expresiones regulares y traducir:

 def normalize_unicode(s): return ''.join([ unichr(k) if k < 0x10000 else 0xfffd for k in [ord(c) for c in s]])