Yo creo que ese no es el problema.
La clave es saber por qué quieres hacer todo esto.
Y para resolver todos los problemas que tienes hay que saber la
codificación de cada una de las partes, de las herramientas que estás usando.
¿En qué codificación está trabajando la base de datos? ¿En qué está la información que recibes? ¿cuál es la codificación de la terminal en la que muestras la información?
Perl es muy bueno haciendo transformaciones de caracteres, de forma automática, pero siempre que le sepamos decir en qué está codificada la entrada y la salida que queremos.
Por ejemplo, yo trabajo desde hace ya tiempo con codificación UTF-8, tanto en la terminal como en los archivos como en la base de datos.
Entonces, supongamos que yo quiero transformar un texto escrito en UTF-8, a una codificación ISO-8859-1. Este programa puede servir de ejemplo:
Using perl Syntax Highlighting
#!/usr/bin/env perl
#
use utf8;
use open OUT => ':encoding(iso-8859-1)';
use feature 'say';
my $texto = "La dueña del camión de cigüeñas llegó vacío.";
say $texto;
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
Si este programa lo ejecuto en mi terminal (que trabaja en codificación UTF-8), veo algo como esto:
La due�a del cami�n de cig�e�as lleg� vac�o.Vamos, muchos caracteres "raros". En realidad, no son raros, sino que están en una codificación distinta a la que trabaja mi terminal, y al intentar representarlos, se da cuenta que hay "errores", o caracteres que no es capaz de interpretar, por lo que saca esos caracteres con interrogantes.
Si pasamos la salida por un volcado hexadecimal empezamos a ver el verdadero contenido:
Using text Syntax Highlighting
> ./kk.pl|hexdump -C
00000000 4c 61 20 64 75 65 f1 61 20 64 65 6c 20 63 61 6d |La due.a del cam|
00000010 69 f3 6e 20 64 65 20 63 69 67 fc 65 f1 61 73 20 |i.n de cig.e.as |
00000020 6c 6c 65 67 f3 20 76 61 63 ed 6f 2e 0a |lleg. vac.o..|
0000002d
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
Vemos que los caracteres tildados están convertidos a un único byte, no a dos bytes como sería normal si estuviera codificado en UTF-8. Vemos entonces que Perl ha hecho bien su trabajo: ha sacado el $texto en la codificación que le pedíamos.
Si guardamos la salida a un archivo de texto,
Using text Syntax Highlighting
> ./kk.pl > kk.txt
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
y cargamos el texto en un editor capaz de entender diversas codificaciones (por ejemplo, kate, en Linux),
Using text Syntax Highlighting
> kate kk.txt
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
entonces ya vemos el texto bien:
La dueña del camión de cigüeñas llegó vacío. (kate entiende que está codificado en ISO-8859-1 y nos muestra los caracteres correctos).
Como ves, no he tenido que hacer ninguna conversión. Solo le he dicho en qué estaba el $texto original (el pragma 'use utf8;' indica que el programa está codificado en UTF-8) y cómo quiero que sea la salida (con el pragma 'use open' le indico que la salida estándar será en otra codificación). Al hacer el say(), Perl hace la transliteración de caracteres.
Si hubiera que hacer un cambio entre... pongamos un archivo y una base de datos, lo recomendable sería usar las funciones de cambio de codificación que trae el módulo Encode.
Entonces, todo lo que leemos del archivo externo se decodifica (función decode()) a la forma interna en la que Perl almacena caracteres. Y luego, antes de sacarlo hacia la base de datos, lo codifico (función encode()) a la codificación que espera esa base de datos.
La estrategia de "filtrar" los caracteres que recibo, cambiándolos por otros, no es aconsejable, sobre todo porque el número de combinaciones puede ser muy grande.
Salvo... que adoptes una regla sencilla: si el carácter que recibo no es ninguno de los conocidos, lo cambio a un carácter neutro. El resto, lo cambio con tr/// o con s///.