• Publicidad

[Unicode Blocks] Codificación de binarios + base PostgreSQL

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Re: [Unicode Blocks] Codificación de binarios + base Postgre

Notapor explorer » 2013-01-19 11:35 @524

reLlene escribiste:una buena noticia: le he echado un ojo a las codificaciones estándares esas que me has pasado y de PURA casualidad (o quizás no tanta, seguir leyendo) me topé con la que creeeo que tienen estos binarios. Hablo de la Windows-1252 ó CP-1252, una codificación del alfabeto latino que DOS y Windows trata, parece también ser Occidental.
Pues no... si te fijas en la tabla de caracteres, verás que 0xDD es el carácter 'Ý', y no el 'i' que necesitas.

Esa es una de las primeras codificaciones que analicé, pero con ver ese carácter ya te das cuenta de que no es una Windows-1252.

reLlene escribiste:Es entonces que me digné a consultar con

Sintáxis: [ Descargar ] [ Ocultar ]
Using sql Syntax Highlighting
  1.  SHOW client_encoding
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


y esto me devolvió lo que parece es la codificación cliente (no servidor) de la base actual donde hago la consulta: SQL_ASCII.
Eso ya lo sabíamos: es lo que aparece en la tabla que publicaste en el primer mensaje. Es la codificación con la que está trabajando el servidor, en esa base de datos.


reLlene escribiste:Traté de cambiarla con SET client_encoding TO 'UTF8' para ver si conseguía algo, pero nada, al volver a consultar con SHOW client_encoding, otra vez: SQL_ASCII.
No, no es así. Cuando tu pones que la codificación del cliente es una determinada, estás indicando en qué codificación están escritos los datos que el cliente va a enviar al servidor. No estás cambiando la codificación en la que está trabajando la base de datos. Esa es labor del administrador de base de datos. Lo que sí nos ayuda 'client_encoding' es que la base de datos haga la transformación por nosotros, pero...

reLlene escribiste:
"The SQL_ASCII setting behaves considerably differently from the other settings. When the server character set is SQL_ASCII, the server interprets byte values 0-127 according to the ASCII standard, while byte values 128-255 are taken as uninterpreted characters. No encoding conversion will be done when the setting is SQL_ASCII. Thus, this setting is not so much a declaration that a specific encoding is in use, as a declaration of ignorance about the encoding. In most cases, if you are working with any non-ASCII data, it is unwise to use the SQL_ASCII setting, because PostgreSQL will be unable to help you by converting or validating non-ASCII characters."
... quiere decir que cuando estamos trabajando con una base de datos que está codificada en SQL_ASCII, no va a realizar ninguna conversión. Simplemente, quiere decir, que no sabe en qué codificación estarán los bytes que le lleguen, así que deja en manos del programador decidir qué hacer. Así que esta puede ser la explicación de por qué el PostgreSQL no ha realizado ninguna conversión y ha dado el fallo anterior. Así, aunque le pongas que tus datos están UTF8, no hará ninguna conversión con ellos.

Quizás la solución sea pasar los datos a una codificación de caracteres de un solo byte por carácter (latin1 o latin9 -la ISO-8859-15, por ejemplo-) y mandar los datos tal cual a la base de datos.

reLlene escribiste:Luego, notaba que al hacer el reemplazo de bytes en los binarios (aquellos que estaban dentro del rango 0x80-0xFF), todavía me restaban otros que, viendo el binario volcando en hexadecimal, llevaban la secuencia EF BF BD (los 3 consecutivos) para representar un 'Unicode block' y si pasaba ese binario a UTF-8 veía un "mojibake", es decir, si contaba con la siguiente secuencia en hexadecimal: 0x66 0xEF 0xBF 0xBD 0x72, desde un editor de texto como el gedit veía f�r, donde el primer y último carácter se logra representar correctamente pero no así los 3 dentro. :?
Te explico: en ocasiones, cuando tenemos un texto y le decimos a un sistema que ese texto está codificado en UTF8, se lo pasa a las tablas de traducción para pasarlo a la codificación Unicode o cualquier otra codificación con la que ese sistema trabaje internamente (Perl trabaja internamiento con Unicode, por ejemplo). Entonces, mientras se está haciendo esa traducción, de repente se encuentra con un carácter que no corresponde con un flujo normal de UTF8 (el texto estaba mal o realmente no estaba codificado en UTF8). Entonces, el estándar dice que en esos casos, el traductor debe descartar el o los bytes que están mal codificados y representarlos por el carácter Unicode U+FFFD ('�') para que el usuario sepa, visualmente, que ahí el traductor ha encontrado algo que no ha sabido traducir a código Unicode. Cuando, de vuelta atrás, queremos grabar la información en otro sitio, el traductor interno repite el proceso, pero esta vez de pasar de Unicode a la codificación con la que queremos grabar los datos. Y resulta que el carácter U+FFFD Unicode se transforma en la secuencia 0xEF 0xBF 0xBD, bajo la codificación UTF8.

Entonces... el problema viene de antes: si vemos en algún momento el carácter '�' es porque seguramente a) el texto no está bien codificado, o b) no es la codificación correcta la que estamos indicando.

reLlene escribiste:El punto es... que parece que en donde están estos últimos hexadecimales (los que se encuentran contiguos: EF BF BD) se pierde el byte original que debe ser mostrado. Con esto me refiero a que en TODO lugar dónde se encuentren estos bytes consecutivos puede haber tanto una 'á' cómo una 'é', una 'í', un camello, un delfín o lo que fuere, pero SE DESCONOCE.
Todo depende de la codificación: si se hace mal, se pueden perder caracteres, o peor: duplicarles. La presencia de esa secuencia te dice que es una secuencia UTF8 que representa al carácter diamante, que se llama replacement character, y sirve para indicar que ahí debía ir un carácter pero que no ha sabido pasar a UTF8.

reLlene escribiste:Pero no hay rastro alguno, ni un byte antes ni después del que fiarme para poder hacer el reemplazo a como debo.
Según el archivo que pasaste, se trata de una codificación prácticamente idéntica a una latin1 o latin9. Entonces, yo lo que haría sería:
  • Filtrar los archivos de entrada, para que los caracteres insidiosos sean transformados a una codificación conocida, por ejemplo la iso-8859-15:

    perl -pe 'tr/\xDD\xAC\xBE/\xED\xBA\xF3/;' input.txt > output.txt

    O incluso hacer la transformación en el propio documento:

    perl -p -i.bak -e 'tr/\xDD\xAC\xBE/\xED\xBA\xF3/;' input.txt
  • Ya solo queda hacer los UPDATE a la base de datos. Como sabemos que no va a realizar ninguna transformación, pues los guardará tal cual se los damos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Publicidad

Re: [Unicode Blocks] Codificación de binarios + base Postgre

Notapor explorer » 2013-01-19 11:36 @525

reLlene escribiste:una buena noticia: le he echado un ojo a las codificaciones estándares esas que me has pasado y de PURA casualidad (o quizás no tanta, seguir leyendo) me topé con la que creeeo que tienen estos binarios. Hablo de la Windows-1252 ó CP-1252, una codificación del alfabeto latino que DOS y Windows trata, parece también ser Occidental.
Pues no... si te fijas en la tabla de caracteres, verás que 0xDD es el carácter 'Ý', y no el 'i' que necesitas.

Esa es una de las primeras codificaciones que analicé, pero con ver ese carácter ya te das cuenta de que no es una Windows-1252.

reLlene escribiste:Es entonces que me digné a consultar con

Sintáxis: [ Descargar ] [ Ocultar ]
Using sql Syntax Highlighting
  1.  SHOW client_encoding
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


y esto me devolvió lo que parece es la codificación cliente (no servidor) de la base actual donde hago la consulta: SQL_ASCII.
Eso ya lo sabíamos: es lo que aparece en la tabla que publicaste en el primer mensaje. Es la codificación con la que está trabajando el servidor, en esa base de datos.


reLlene escribiste:Traté de cambiarla con SET client_encoding TO 'UTF8' para ver si conseguía algo, pero nada, al volver a consultar con SHOW client_encoding, otra vez: SQL_ASCII.
No, no es así. Cuando tu pones que la codificación del cliente es una determinada, estás indicando en qué codificación están escritos los datos que el cliente va a enviar al servidor. No estás cambiando la codificación en la que está trabajando la base de datos. Esa es labor del administrador de base de datos. Lo que sí nos ayuda 'client_encoding' es que la base de datos haga la transformación por nosotros, pero... en este caso... no nos sirve, porque...

reLlene escribiste:
"The SQL_ASCII setting behaves considerably differently from the other settings. When the server character set is SQL_ASCII, the server interprets byte values 0-127 according to the ASCII standard, while byte values 128-255 are taken as uninterpreted characters. No encoding conversion will be done when the setting is SQL_ASCII. Thus, this setting is not so much a declaration that a specific encoding is in use, as a declaration of ignorance about the encoding. In most cases, if you are working with any non-ASCII data, it is unwise to use the SQL_ASCII setting, because PostgreSQL will be unable to help you by converting or validating non-ASCII characters."
... quiere decir que cuando estamos trabajando con una base de datos que está codificada en SQL_ASCII, no va a realizar ninguna conversión. Simplemente, quiere decir, que no sabe en qué codificación estarán los bytes que le lleguen, así que deja en manos del programador decidir qué hacer. Así que esta puede ser la explicación de por qué el PostgreSQL no ha realizado ninguna conversión y ha dado el fallo anterior. Así, aunque le pongas que tus datos están UTF8, no hará ninguna conversión con ellos.

Quizás la solución sea pasar los datos a una codificación de caracteres de un solo byte por carácter (latin1 o latin9 -la ISO-8859-15, por ejemplo-) y mandar los datos tal cual a la base de datos.

reLlene escribiste:Luego, notaba que al hacer el reemplazo de bytes en los binarios (aquellos que estaban dentro del rango 0x80-0xFF), todavía me restaban otros que, viendo el binario volcando en hexadecimal, llevaban la secuencia EF BF BD (los 3 consecutivos) para representar un 'Unicode block' y si pasaba ese binario a UTF-8 veía un "mojibake", es decir, si contaba con la siguiente secuencia en hexadecimal: 0x66 0xEF 0xBF 0xBD 0x72, desde un editor de texto como el gedit veía f�r, donde el primer y último carácter se logra representar correctamente pero no así los 3 dentro. :?
Te explico: en ocasiones, cuando tenemos un texto y le decimos a un sistema que ese texto está codificado en UTF8, se lo pasa a las tablas de traducción para pasarlo a la codificación Unicode o cualquier otra codificación con la que ese sistema trabaje internamente (Perl trabaja internamiento con Unicode, por ejemplo). Entonces, mientras se está haciendo esa traducción, de repente se encuentra con un carácter que no corresponde con un flujo normal de UTF8 (el texto estaba mal o realmente no estaba codificado en UTF8). Entonces, el estándar dice que en esos casos, el traductor debe descartar el o los bytes que están mal codificados y representarlos por el carácter Unicode U+FFFD ('�') para que el usuario sepa, visualmente, que ahí el traductor ha encontrado algo que no ha sabido traducir a código Unicode. Cuando, de vuelta atrás, queremos grabar la información en otro sitio, el traductor interno repite el proceso, pero esta vez de pasar de Unicode a la codificación con la que queremos grabar los datos. Y resulta que el carácter U+FFFD Unicode se transforma en la secuencia 0xEF 0xBF 0xBD, bajo la codificación UTF8.

Entonces... el problema viene de antes: si vemos en algún momento el carácter '�' es porque seguramente a) el texto no está bien codificado, o b) no es la codificación correcta la que estamos indicando.

reLlene escribiste:El punto es... que parece que en donde están estos últimos hexadecimales (los que se encuentran contiguos: EF BF BD) se pierde el byte original que debe ser mostrado. Con esto me refiero a que en TODO lugar dónde se encuentren estos bytes consecutivos puede haber tanto una 'á' cómo una 'é', una 'í', un camello, un delfín o lo que fuere, pero SE DESCONOCE.
Todo depende de la codificación: si se hace mal, se pueden perder caracteres, o peor: duplicarles. La presencia de esa secuencia te dice que es una secuencia UTF8 que representa al carácter diamante, que se llama replacement character, y sirve para indicar que ahí debía ir un carácter pero que no ha sabido pasar a UTF8.

reLlene escribiste:Pero no hay rastro alguno, ni un byte antes ni después del que fiarme para poder hacer el reemplazo a como debo.
Según el archivo que pasaste, se trata de una codificación prácticamente idéntica a una latin1 o latin9. Entonces, yo lo que haría sería:
  1. Filtrar los archivos de entrada, para que los caracteres insidiosos sean transformados a una codificación conocida, por ejemplo la iso-8859-15:

    perl -pe 'tr/\xDD\xAC\xBE/\xED\xBA\xF3/' input.txt > output.txt

    O incluso hacer la transformación en el propio documento:

    perl -p -i.bak -e 'tr/\xDD\xAC\xBE/\xED\xBA\xF3/' input.txt
  2. Ya solo queda hacer los UPDATE a la base de datos. Como sabemos que no va a realizar ninguna transformación, pues los guardará tal cual se los damos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Anterior

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 56 invitados

cron