Buscar en este blog

jueves, 18 de abril de 2013

Codificación correcta de DTE y IECV en ISO-8859-1



Codificación correcta de DTE y IECV en ISO-8859-1


Problema

Se requiere generar los archivos DTE o IECV de un determinado cliente. Este envía archivos planos con la información necesaria para construir dichos documentos. Estos archivos planos pueden estar codificados en formatos tales como: : UTF-8, ANSI, UTF-16, UNICODE.

Al momento de leer estos archivos planos para extraer la información de ellos muchas veces la lectura de los mismos arroja errores de caracteres que se pierden o no pueden ser leídos por pertenecer a codificaciones distintas a las que realmente se necesitan. Un ejemplo de esto sería el envío de un archivo plano en formato UNIX.

La perdida de caracteres o la mala interpretación de los mismos repercute al momento de realizar cualquier procesamiento sobre ellos, dando lugar a errores al momento de generar nuestros archivos de salida.

Ejemplo:

Si tenemos una cadena de caracteres como la siguiente,

“El griego antiguo(Ἀρχαία Ἑλληνική Arkhaía Hellēnikḗ) se refiere al idioma griego que existió…”

He intentamos leer esta información utilizando la codificación ISO-8859-1 obtendríamos lo siguiente:

“El griego antiguo((err)(err)(err)(err)(err)(err) (err)(err)(err)(err)(err)(err)(err)(err) Arkhaía Hell(err)nik(err)) ) se refiere al idioma griego que existió…”

Este es un caso extremo para presentar el problema, de todas formas ilustra el cómo pueden perderse caracteres al momento de realizar nuestros procesamientos.

Si llevamos este ejemplo a la vida real de la Factura Electrónica podríamos encontrarnos con este tipo de despliegue en nuestros archivos.

<RznSoc>CONSTRUCTORA RE¥ACA SA</RznSoc>

Donde el caracter ¥ no pertenece realmente al valor del tag, si no que, fue leído erróneamente al momento de su proceso. Posteriormente fue plasmado en un documento IECV.



Análisis

Para evitar tener este tipo de problemas  es necesario crear una clase que permita leer el archivo plano enviado por el cliente y validar el set de caracteres antes de ser procesado. De esta forma podremos saber de ante mano que debemos arreglar o si todo está en condiciones para iniciar nuestro proceso.


  •  La clase debe poder leer un archivo plano independiente del set de caracteres utilizado para su construcción.

  •  Se debe leer cada línea del archivo para establecer detenidamente donde hay problemas.

  •  La clase debe entregar el número de línea del archivo, el contenido y cuantos errores de conversión encontró.

Bueno como siempre, aqui les dejo la clase para que puedan analizarla y agregarla a sus proyectos.

Clase C# ReplacementFallback ISO-8859-1

NOTA: La clase es operativa pero no esta completamente terminada.

Comentarios del desarrollo.

Para poder rescatar la mayoría de los caracteres que se encuentran disponibles en los archivos planos, es necesario indicar al objeto StreamReader que sistema de codificación se utilizara para abrir el archivo, en este caso yo utilice la codificación UTF-8. Esto le indica al procesador que abra el archivo simulando el envío de un cliente en este formato.


#region Ejemplo de lectura de un archivo plano enviado por un cliente

   ////
   //// Cree el encoding base para abrir el archivo
   Encoding utf = Encoding.UTF8;

   ////
   //// Abra el archivo plano utilizando la codificación
   //// Donde uri representa la fullpath del archivo plano,
   //// ejemplo: 'c:\\archivoPlano.txt'
   using (StreamReader sr = new StreamReader(uri, utf ))
   {
      
         ////
         //// Aquí lea el archivo ..........  
         //// Supondremos que este archivo solo tiene una linea.
         while( sr.Peek()!=-1 )
         {
             string lineaOriginal = sr.ReadLine();
         }

   }

#endregion 


Esa operación nos regresará la siguiente linea:

"El griego antiguo(Ἀρχαία Ἑλληνική Arkhaía Hellēnikḗ)"

Ahora bien para poder determinar que caracteres de esta cadena son suceptibles de ser representados en la codificación ISO-8859-1 debemos comprobar los bytes representativos, para esto podemos utilizar la siguiente secuencia:



#region Secuencia de comprobación de caracteres ISO-8859-1

   ////
   //// Bibliotecas
   using System;
   using System.Collections.Generic;
   using System.Linq;
   using System.Text; 
   using System.IO;

   ////
   //// Esta linea representa la linea leída desde el archivo plano
   //// en la rutina anterior.
   string lineaOriginal = "El griego antiguo(Ἀρχαία Ἑλληνική Arkhaía Hellēnikḗ)";

   ////
   //// Cree el encoding de la Factura Electrónica.
   //// Indicamos que cuando no pueda interpretar un caracter
   //// deje en su lugar:(err). Esto nos ayudará a contar los 
   //// caracteres no validos.
   Encoding iso = Encoding.GetEncoding("ISO-8859-1",
                                          new EncoderReplacementFallback("(err)"),
                                             new DecoderReplacementFallback("(error)"));

   ////
   //// Cree un arreglo de bytes del mismo tamaño de la cadena original
   //// Para almacenar el resultado de la codificacion.
   byte[] clonLineaOriginal = new byte[iso.GetByteCount(lineaOriginal)];

   ////
   //// Transforme la cadena original a su representacion ISO-8859-1 en bytes
   int numberOfEncodedBytes = iso.GetBytes(lineaOriginal, 0, lineaOriginal.Length, clonLineaOriginal , 0);

   ////
   //// Recupere los caracteres codificados en ISO-8859-1
   string lineaNueva = iso.GetString(clonLineaOriginal);


   ////
   //// Ahora finalizada la codificacion de los caracteres podemos 
   //// contar aquellos que no corresponden a la codificacion ISO-8859-1
   string pattern = @"\(err\)";
   MatchCollection mc = Regex.Matches(lineaCodificada, pattern);




#endregion 

El resultado de aplicar esta rutina nos entregará la siguiente información:

Linea Original:
El griego antiguo(Ἀρχαία Ἑλληνική Arkhaía Hellēnikḗ)

Linea Codificada:
El griego antiguo((err)(err)(err)(err)(err)(err) (err)(err)(err)(err)(err)(err)(err)(err) Arkhaía Hell(err)nik(err)) 

Errores   
La cantidad de errores de transformación de caracteres es 16, este valor se accede desde
mc.Count

Conclusión:

Con esta información y utilizando estas rutinas podría construír uno o dos funciones que le permitieran validar los caracteres de sus archivos planos antes de procesarlos y generar documentos electrónicos tributarios. No entraré en detalles de como realizar este proceso, pero de todas formas les deje un link con una pequeña clase que podría ayudarlos a crear las suyas.


No hay comentarios:

Publicar un comentario