“Untranslatable character” y EF BF BD

Resulta que te pasan un fichero para cargar en tu tabla en Teradata. Resulta que el fichero es de unos 2GB (y decides cargarlo con fastload). Resulta que el fichero es de texto delimitado tipo csv (comma separated values). Resulta que el fichero es UTF-8 (porque el sistema origen utiliza UTF-8). Resulta que tus tablas son LATIN (aunque no debería ser un problema, porque los caracteres que van a llegar en el fichero deberían ser sólo caracteres occidentales).

Lo normal.

Te pones a ello y utilizas fastload -c UTF8 (también podrías haber usado SET SESSION CHARSET).

Y entonces aparecen un monton de filas en la tabla de error 1 con el código 6706 (“The string contains an untranslatable character“).

Mierda.

Y ahí empieza lo bueno…

Una investigación sobre los datos problemáticos nos llevan a descubrir que la inmensa mayoría presentan cadenas de texto que contienen los tres bytes EF BF BD.

¿Y qué significan esos tres bytes? Pues significan que el sistema origen debería haber cargado datos UTF-8 exclusivamente, pero en realidad no fue así (al menos para una parte de ellos).

Los tres bytes constituyen la codificación UTF-8 del UNICODE U+FFFD, “REPLACEMENT CHARACTER”, y no son otra cosa que el rombito negro con una pequeña interrogación dentro que se puede ver surfeando la web cuando la tabla de códigos de la página HTML no se corresponde con la que espera el navegador.

Es la forma de decir “Eh, que estos bytes que me mandas no son UTF-8 (la codificación de los caracteres tiene unas reglas específicas en cuanto a bytes y sus bits). No sé lo que es, así que pongo el simbolito (“<?>”) en su lugar.”

Es algo parecido a lo que hacen muchas aplicaciones cuando reciben caracteres que no pueden representar con la tabla de códigos que están utilizando y los sustituyen por una interrogación (sql*plus lo hace así, por ejemplo).

Evidentemente, no existe ningún símbolo LATIN correspondiente al “REPLACEMENT CHARACTER”, por lo que fastload deriva los registros del fichero que lo contienen a la tabla de error 1 con el código 6706, ya que no lo puede traducir.

sed at rescue

Bueno, pues sabiendo que los tres bytes corresponden al símbolo que se utiliza como sustitución de un caracter erróneo, ¿por qué no hacemos nosotros el tarbajo previo y lo sustituímos por una interrogación simple (3F en hexadecimal), que sí se podrá traducir a LATIN?

OK. Recurrimos a sed y su funcionalidad de sustitución de códigos hexadecimales:

$ > sed "s/\xEF\xBF\xBD/\x3F/g" file1.csv > file2.csv

A partir de ahí, utilizando file2.csv conseguimos cargar los datos sin pérdida de información, y la tabla de error 1 está vacía al final del proceso.

Saludos.

Carlos.

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: