• Publicidad

Problemas con ñ y EBCDIC (Convert::IBM390)

Así que programas sin strict y las expresiones regulares son otro modo de hablar. Aquí encontrarás respuestas de nivel avanzado, no recomendable para los débiles de corazón.

Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor puchumx » 2012-03-28 14:30 @645

Estimados:

Tengo un problema con Perl y las "ñ"... El tema es así...

A través de un perl genero un spool y lo paso a EBCDIC con la librería "Convert::IBM390". El tema es que cuando abro los archivos con un editor de texto (ultraedit) las 'ñ' me figuran con "?".

Pasé los archivos en modo binario. Además, cuando me conecto desde sqlplus a Unix pasa lo siguiente:

Imagen
(le quité algunos datos posiblemente sensibles por mi trabajo :) )

Por lo que pueden ver, parece ser un problema de las variables de entorno de Unix... El tema es que de Unix dicen que está todo bien configurado... :evil: Además, me genera bien el archivo si genero el mismo sin pasarlo a ebcdic (previo seteo del nls_lang), pero cuando lo paso a ebcdic con la librería y después lo paso a ascii nuevamente con el ultraedit, me aparece el carácter "#".

Trabajo con Unix y tiene las siguientes variables seteadas:

locale:
LANG=en_US
LC_COLLATE="en_US"
LC_CTYPE="en_US"
LC_MONETARY="en_US"
LC_NUMERIC="en_US"
LC_TIME="en_US"
LC_MESSAGES="en_US"
LC_ALL=

export(las que creo que son importantes)
LANG="en_US"
SHELL="/usr/bin/ksh"

Además en el perl que genera el archivo tengo lo siguiente:
use POSIX qw/ strftime/; #permite usar strftime para tomar la fecha
use Convert::IBM390 qw(:all); #permite hacer la compresión
# Se setea el codepage requerido de EBCDIC
set_codepage('CP00284');

(entre otras cosas)

y la función que "comento" para que codifique en ebcdic o no es la siguiente:
open(ARCHIVO_SALIDA,">".$nombreArchivo)
or die("No se pudo crear el archivo: ".$nombreArchivo);

binmode ARCHIVO_SALIDA;

#Contador de registros escritos
my $cantidadRegistrosEscritos = 0;

while (my @array = $sth->fetchrow_array()) {

@array=packeb($formatoRegistro, @array);

print ARCHIVO_SALIDA @array; #imprimimos un array

if ($flagSeparador eq "SI") {
print ARCHIVO_SALIDA "\n"; #un separador de nueva línea
}

$cantRegistrosEcritos++;

}
close(ARCHIVO_SALIDA);


Intenté hacer lo que dice en este hilo, pero no resultó... Me dice que no puedo setear "locale". No sé por qué...

¡Ayuda! Estoy desesperado ya... :cry: y encima no sé nada de Perl... :oops:

Gracias de antemano...
puchumx
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2012-03-28 13:42 @612

Publicidad

Re: Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor explorer » 2012-03-28 17:20 @764

Bienvenido a los foros de Perl en Español, puchumx.

Necesitaríamos saber con qué Perl estás trabajando. Haz un perl -V

En la documentación oficial de Perl hay un documento dedicado exclusivamente a EBCDIC, contando sus particularidades (que son bastantes) (en tu propio ordenador, deberías poder leerlo localmente con el comando perldoc perlebcdic)

Por lo que sale en la imagen, parece que si indicamos que queremos trabajar en ISO-8859-1, vemos la 'ñ'. Ya que no conozco nada de EBCDIC, a lo mejor lo que voy a decir a continuación es una tontería, pero, en cuestión de codificaciones, no solo basta con saber en qué codificación está trabajando la shell o los programas de aplicación que estamos usando (como las bases de datos), sino que, además, hay que conocer la codificación de la terminal en la que estamos.

Eso quiere decir que, a lo mejor, en la primera consulta que haces, al ver los caracteres '?', resulta que sí es la letra 'ñ', pero en una codificación que es distinta de la codificación en la que está trabajando la terminal. Cuando lo cambias NLS_LANG a iso-8859-1, y sale en pantalla, la vemos porque Oracle en ese momento sabe la codificación en la que estamos trabajando (la aplicación de usuario Y la terminal).

«Setting the NLS_LANG environment parameter is the simplest way to specify locale behavior for Oracle software. It sets the language and territory used by the client application and the database server. It also indicates the client's character set, which corresponds to the character set for data to be entered or displayed by a client program.» FAQ

Las variables de entorno Unix que sacas nos dicen que estás en en_US para el 'collating' (ordenación de letras), pero no nos dicen nada de la codificación, así que estarán tomando la de por defecto del sistema.

Así que... ¿en qué estamos trabajando en el sistema? ¿En EBCDIC o en otra codificación?

En el perlebcdic tienes ejemplos de cómo usar (a partir de Perl v5.8) el módulo Encode para pasar de una codificación a otra, que puedes usar también a parte de Convert::IBM390.

Una cosa: dices que el problema está a la hora de abrir el fichero con el Ultraedit, que no salen bien los caracteres. ¿En qué codificación está el Ultraedit en ese momento? (Menú Ver->Cambiar codificación) A lo mejor puedes cambiar a una correcta y entonces sabrás en qué codificación está realmente el archivo.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor puchumx » 2012-03-29 08:47 @408

Genio, gracias por responder y por la bienvenida.

Te comento: estoy trabajando con la versión 5.8 de Perl. La codificación del UltraEdit que estaba usando era la "1252 (ANSI - Latín I)" (ahora la pasé a "28591 (ISO 8859-1 Latín I)") pero no funcionó.

Usamos la librería Convert::IBM390 y está bien configurada (aparentemente, es la correcta, la 284), así que tendría que leer cómo combinarla con la "Encode"...

Algo que me llamo la atención es lo que está seteado en la base de datos, que no corresponde a lo de Unix (no sé si por ahí viene el problema):

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
NLS_LANGUAGE: LATIN AMERICAN SPANISH
NLS_DATE_LANGUAGE: LATIN AMERICAN SPANISH
NLS_CHARACTERSET: WE8ISO8859P1
NLS_SORT: SPANISH
NLS_NCHAR_CHARACTERSET: AL16UTF16
NLS_COMP: BINARY
NLS_LENGTH_SEMANTICS: BYTE
NLS_NCHAR_CONV_EXCP: FALSE
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


En cambio en Unix dice que estoy en "US", cuando debería estar en "ES", ¿no?

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
LANG=en_US
LC_COLLATE="en_US"
LC_CTYPE="en_US"
LC_MONETARY="en_US"
LC_NUMERIC="en_US"
LC_TIME="en_US"
LC_MESSAGES="en_US"
LC_ALL=
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


También me llama mucho la atención lo siguiente:
* CON LNS_LANG no seteado
Sin comprimir -> Ñ = ?
Usando Convert::IBM390, y Uedit de EBCDIC a ascii -> Ñ = ?

* CON LNS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
Sin comprimir -> Ñ = Ñ
Usando Convert::IBM390, y Uedit de EBCDIC a ascii -> Ñ=# , ñ=|

Desde Unix me dicen que está todo bien, que el charset está funcionando bien y que ISO8859-1 es la configuración... :roll:

¡Voy a leer lo que me pasaste de la documentación oficial de Perl a ver qué encuentro!

¡Ah!, intenté setear la variable LC_ALL para decirle a Perl que estoy usando caracteres españoles, pero al setearlo en el perl así:

use POSIX qw(locale_h);
setlocale(
LC_ALL,
"es_ES.ISO-8859-1"
)
or die "Fallo al setear la variable LC_ALL";


al correr el perl, en Unix me figura:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LC_ALL = "es_ES.ISO-8859-1",
LC__FASTMSG = "true",
LANG = "en_US"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").


¡Gracias explorer!
puchumx
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2012-03-28 13:42 @612

Re: Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor explorer » 2012-03-29 11:11 @508

puchumx escribiste:estoy trabajando con la versión 5.8 de Perl.
Pero, ¿cuál? ¿La v5.8.0, la v5.8.8...? Es que de una versión a otra sí que pueden cambiar mucho las cosas, sobre todo en el tema de codificaciones.

puchumx escribiste:La codificación del UltraEdit que estaba usando era la "1252 (ANSI - Latín I)" (ahora la pasé a "28591 (ISO 8859-1 Latín I)") pero no funcionó.
Se trata de "Ver" en qué codificación está. Si no es con ninguna de esas, pues hay que seguir probando. Yo, en Linux, cuando no sé qué es lo que estoy viendo, uso un volcado hexadecimal para "ver los bytes":
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
explorer@casa:/media/500_1/home/explorer/Documentos/Desarrollo> hexdump -C donquijoteparrafo1.txt
00000000  45 6e 20 75 6e 20 6c 75  67 61 72 20 64 65 20 6c  |En un lugar de l|
00000010  61 20 4d 61 6e 63 68 61  2c 20 64 65 20 63 75 79  |a Mancha, de cuy|
00000020  6f 20 6e 6f 6d 62 72 65  20 6e 6f 20 71 75 69 65  |o nombre no quie|
00000030  72 6f 20 61 63 6f 72 64  61 72 6d 65 2c 20 6e 6f  |ro acordarme, no|
00000040  20 68 61 20 6d 75 63 68  6f 0a 74 69 65 6d 70 6f  | ha mucho.tiempo|
00000050  20 71 75 65 20 76 69 76  c3 ad 61 20 75 6e 20 68  | que viv..a un h|
00000060  69 64 61 6c 67 6f 20 64  65 20 6c 6f 73 20 64 65  |idalgo de los de|
00000070  20 6c 61 6e 7a 61 20 65  6e 20 61 73 74 69 6c 6c  | lanza en astill|
00000080  65 72 6f 2c 20 61 64 61  72 67 61 20 61 6e 74 69  |ero, adarga anti|
00000090  67 75 61 2c 0a 72 6f 63  c3 ad 6e 20 66 6c 61 63  |gua,.roc..n flac|
000000a0  6f 20 79 20 67 61 6c 67  6f 20 63 6f 72 72 65 64  |o y galgo corred|
000000b0  6f 72 2e 20 55 6e 61 20  6f 6c 6c 61 20 64 65 20  |or. Una olla de |
000000c0  61 6c 67 6f 20 6d c3 a1  73 20 76 61 63 61 20 71  |algo m..s vaca q|
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Aquí ya veo que los caracteres tildados ocupan dos bytes, y que todos ellos comienzan con el byte 0xc3, así que esto es un archivo escrito en UTF8.

También suelo usar el comando 'file':
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
explorer@casa:/media/500_1/home/explorer/Documentos/Desarrollo> file donquijoteparrafo1.txt
donquijoteparrafo1.txt: UTF-8 Unicode text
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Es más rápido :)

Bueno, pues si no es iso-8859-1 ni la latin1 versión 1252 de Windows, será otra (sospecho que puede ser EBCDIC :) )

puchumx escribiste:Usamos la librería Convert::IBM390 y está bien configurada (aparentemente, es la correcta, la 284), así que tendría que leer cómo combinarla con la "Encode"...
Pues si funciona bien, déjala como está.

puchumx escribiste:Algo que me llamó la atención es lo que está seteado en la base de datos, que no corresponde a lo de Unix (no sé si por ahí viene el problema):
...
En cambio en Unix dice que estoy en "US", cuando debería estar en "ES", ¿no?
Bueno, entre la versión española y la norteamericana, hay unas diferencias, como el 'collating' (ordenación), fechas, horas, caracteres de separación de los millares y decimales... Pero esto se refiere a la localización (particularidades de cada país). Estábamos hablando de la codificación (tabla de caracteres).

puchumx escribiste:También me llama mucho la atención lo siguiente:
* CON LNS_LANG no seteado
Sin comprimir -> Ñ = ?
Usando Convert::IBM390, y Uedit de EBCDIC a ascii -> Ñ = ?
Bien... no es ASCII... ¿Qué es? ¿Qué byte(s) es/son?

puchumx escribiste:* CON LNS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
Sin comprimir -> Ñ = Ñ
Usando Convert::IBM390, y Uedit de EBCDIC a ascii -> Ñ=# , ñ=|
La variable de entorno NLS_LAG (que no LNS_LANG) le indica a Oracle que nuestra aplicación/terminal trabaja en esa codificación, así que suponemos que entregará el resultado en esa codificación. Si nuestra terminal también está en is-8859-1, por eso podemos ver bien la 'Ñ' en pantalla. Otra cosa es lo que hace nuestro programa: ¿seguro que sabe que ahora los datos que recibe desde la base de datos están en iso-8859-1?

puchumx escribiste:Desde Unix me dicen que está todo bien, que el charset está funcionando bien y que ISO8859-1 es la configuración... :roll:
Bueno, pues ya tenemos una pista más.

puchumx escribiste:¡Ah!, intenté setear la variable LC_ALL para decirle a Perl que estoy usando caracteres españoles, pero al setearlo en el perl así:

use POSIX qw(locale_h);
setlocale(
LC_ALL,
"es_ES.ISO-8859-1"
)
or die "Fallo al setear la variable LC_ALL";


al correr el perl, en Unix me figura:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LC_ALL = "es_ES.ISO-8859-1",
LC__FASTMSG = "true",
LANG = "en_US"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
Eso quiere decir que en ese sistema no están instaladas las tablas de localización para es_ES.ISO-8859-1. Deberás pedir a los administradores que las instalen.

Lo tienes comentado en perllocale, sección Permanently fixing your system's locale configuration.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor puchumx » 2012-03-29 12:35 @566

¡Wow! ¡Cuanta info! ¡ja,ja,ja! Gracias, explorer, voy a seguir probando a ver cómo sigo y cuento por acá ¡cómo lo arreglé!

Cualquier duda nueva que me surja la posteo acá :wink:

¡¡¡Gracias de nuevo!!!
puchumx
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2012-03-28 13:42 @612

Re: Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor puchumx » 2012-04-03 14:57 @664

Bueno, encontré una solución :D :D :D :D :D

Paso a ponerla acá por si a alguno le sirve.

Pasos:
1) Como al ejecutar el spool sin usar la librería Convert::IBM390 (para pasar de ascii a ebcdic y viceversa), tuve que setear la variable NLS_LANG y exportarla en unix así:

export NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1

2) En esta página: http://www.tachyonsoft.com/cp00037.htm (perdón si no se puede, pero está buena para buscar los códigos ascii, entre otros) encontré los códigos ascii/ebcdic de cada carácter. (Si le cambias el cp00037 por el que quieras tenes otros juegos de codepages.)

3) Abrí con un editor de texto el cp00037 que tengo instalado en unix y me abría una serie de números ordenados en columnas y filas (esos son los códigos ascii que después la librería va a traducir dependiendo su posición...) Es algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub import {
  2.   set_translation(undef, <<'END EBCDIC');
  3. 00 01 02 03 9C 09 86 7F 97 8D 8E 0B 0C 0D 0E 0F
  4. 10 11 12 13 9D 0A 08 87 18 19 92 8F 1C 1D 1E 1F
  5. 80 81 82 83 84 85 17 1B 88 89 8A 8B 8C 05 06 07
  6. 90 91 16 93 94 95 96 04 98 99 9A 9B 14 15 9E 1A
  7. 20 A0 E2 E4 E0 E1 E3 E5 E7 F1 A2 2E 3C 28 2B 7C
  8. 26 E9 EA EB E8 ED EE EF EC DF 21 24 2A 29 3B AC
  9. 2D 2F C2 C4 C0 C1 C3 C5 C7 D1 A6 2C 25 5F 3E 3F
  10. F8 C9 CA CB C8 CD CE CF CC 60 3A 23 40 27 3D 22
  11. D8 61 62 63 64 65 66 67 68 69 AB BB F0 FD FE B1
  12. B0 6A 6B 6C 6D 6E 6F 70 71 72 AA BA E6 B8 C6 A4
  13. B5 7E 73 74 75 76 77 78 79 7A A1 BF D0 DD DE AE
  14. 5E A3 A5 B7 A9 A7 B6 BC BD BE 5B 5D AF A8 B4 D7
  15. 7B 41 42 43 44 45 46 47 48 49 AD F4 F6 F2 F3 F5
  16. 7D 4A 4B 4C 4D 4E 4F 50 51 52 B9 FB FC F9 FA FF
  17. 5C F7 53 54 55 56 57 58 59 5A B2 D4 D6 D2 D3 D5
  18. 30 31 32 33 34 35 36 37 38 39 B3 DB DC D9 DA 9F
  19. END EBCDIC
  20. } # end import
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


4) Hice un update sobre la base de datos sobre un campo string con varios de los caracteres "raros" del codeset 037 (estimé que ese estaba instalado en el mainframe del IBM) y la mayoría me daba los mismos, pero otros me los cambiaba... He aquí que la 'ñ' y la 'Ñ' estaban, pero en la BD eran otros caracteres.

5) Me fijé en la página los caracteres que tenía en la base de datos que se correspondían con la 'ñ' y 'Ñ' en las bajadas que generaba e intercambié sus códigos ascii en la tabla de arriba (use el codeset ISO-8859-1 porque era el que estaba instalado en unix, según mi admin unix)

6)"Voalá"... Ya me imprimía las 'ñ'... :mrgreen:

Disculpen la mala redacción o si algo no está bien explicado, es solo para que vean cómo lo solucioné y que sirva como guía a alguien más... ¡¡Saludos y gracias explorer por tu ayuda!! :)
puchumx
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2012-03-28 13:42 @612

Re: Problemas con ñ y EBCDIC (Convert::IBM390)

Notapor explorer » 2012-04-03 16:16 @719

Creo que has relatado lo que hace Encode :)

Es decir, si supiéramos en qué codificación está el origen, y como sabemos que debemos pasarlo a iso-8859-1, entonces toda la transformación se hace en un paso con from_to().

De todas formas, enhorabuena. Apuntado queda.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Avanzado

¿Quién está conectado?

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

cron