Conversion Ansi->UTF-8 en Pascal (Delphi – Lazarus – FreePascal)

Qui n’a pas galéré comme moi à recevoir des fichiers provenant de l’extérieur, supposés être en UTF8 mais malheureusement en Ansi.

Et qui n’a pas cherché pendant des heures sur internet comment faire la conversion de tels fichiers ?

Car si php propose des fonctions sur le sujet assez bien documentées, si python offre une bibliothèque également bien documentée, si en language C, on trouve des fonctions de bas niveau permettant de le faire. Quid du Pascal ?

Après avoir chercher durant des heures en vain, et expérimenté différentes solutions voici ce que j’en ai retenu :

  • Avec Windows (pas essayé sur un Linux) si on se contente de lire un fichier ligne à ligne, et de transformer chaque ligne en UTF8 pour finir par l’écrire dans un fichier, chaque ligne sera effectivement convertie puis écrite… en Ansi !!.  Ne comprenant pas pourquoi je constatais cela, j’en ai été convaincu après avoir finit par  afficher la taille en octets de chaque ligne avant écriture (toujours identiques !!)
  • Donc on peut lire le fichier en entrée ligne à ligne mais ensuite, il ne faut plus raisonner en chaîne de caractères : il faut la transformer en tableau de bytes, convertir ce tableau de bytes en UTF8, puis, ne surtout pas re-transformer ce tableau en chaîne, on obtiendrait encore de l’Ansi ! il faut écrire tel quel ce tableau dans le fichier de sortie.

D’où l’usage archaïque (choisis parce que facile à comprendre même pour un débutant) de AssignFile – Reset – ReadLn – CloseFile pour la lecture de chaque ligne.

Et surtout, l’usage de TStream pour écrire le tableau de byte converti en UTF-8 tel quel.

Le coeur de tout ça étant la fonction tab:=System.sysutils.TEncoding.UTF8.GetBytes(instring); qui reçoit la ligne instring qui est supposée être en Ansi, et la convertit en tableau de bytes UTF8.

Voici le code de conversion d’un fichier Ansi (Tresultat est un type record contenant : CR, un integer (code retour) et MSG un string (message de retour))

function AnsiFileToUtf8File2(fin,fout:string): tresultat;
var sligin:ansistring;
    fhin:TextFile;
    i: integer;
    datain:TBytes;
    streamout:tstream;
begin
  Result.CR:=0;
  Result.MSG:='';

  if (fin=fout) then
     begin
        result.CR:=-1;
        Result.MSG:='Les fichiers d''entrée et de sortie ne peuvent pas avoir le même nom'; //ceinture, bretelle + capote
        exit;
     end;


  i:=0;
  if not fileexists(fin) then
     begin
        result.CR:=-1;
        Result.MSG:='Le fichier '+fin+' n''existe pas';  //ceinture, bretelle + capote
        exit;
     end;
  if fileexists(fout) then DeleteFile(fout);

  AssignFile(Fhin,fin);
  {$I-} //La vérification d'E/S est désactivée  //ceinture, bretelle + capote
  Reset(Fhin);
  {$I+} //La vérification d'E/S est activée     //ceinture, bretelle + capote
  if IoResult<>0 then                           //ceinture, bretelle + capote
     begin
        result.CR:=-1;
        Result.MSG:='Impossible d''ouvrir le fichier '+fin+' en lecture';
        exit;
     end;
  streamout := TFileStream.Create(fout, fmcreate );
  try
      while not eof(fhin) do
         begin
            readln(Fhin,sligin);
            sligin:=sligin+#13+#10;   //Readln retire les caractères de saut de ligne donc je dois les remettre
            datain:=TEncoding.UTF8.GetBytes(sligin); // conversion en un tableau de bytes UTF8
            streamout.Seek(0,soFromEnd); //se positionner à la fin du stream, au cas où (sert à rien je sais, est rester à cause de tests précédent)
            streamout.Write(Pointer(datain)^, Length(datain));  //écrit tel quel le tableau de bytes dans le stream.
            inc(i);  //j'aime bien connaitre le nombre d'itération
         end;
  Finally
      CloseFile(Fhin);
     streamout.Free;
  end;
  result.MSG:='Terminé, '+inttostr(i)+' lignes traitées';
end;

 

 

 

 

 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.