Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Conversion de chaînes de caractères : Lingo <-> UTF-8

Compatible Director. Cliquer pour en savoir plus sur les compatibilités.Par Yannick Halloin, le 13 octobre 2005

Yannick Halloin a posté ces 2 fonctions très utiles sur la mailing Pistes-L et nous a autorisé à les recopier ici : un grand merci à lui !

Utilisation : ce code est à placer dans un script d'animation (movie script). A partir de là vous pouvez appeler la fonction LingoStrToUTF8str pour convertir une chaîne de caractère Lingo en une chaîne UTF8 :

maVar = LingoStrToUTF8str("une chaîne de caractères")


… et inversement avec la fonction UTF8StrToLingoStr ;)

on LingoStrToUTF8Str la_chaine
 -- infos sur les block de codes du format unicode (extraites des documents officiels de unicode.org)
 --
 --0000..007F; Basic Latin
 --0080..00FF; Latin-1 Supplement
 --0100..017F; Latin Extended-A
 --0180..024F; Latin Extended-B
 --0250..02AF; IPA Extensions
 --02B0..02FF; Spacing Modifier Letters
 --0300..036F; Combining Diacritical Marks
 --0370..03FF; Greek and Coptic
 --0400..04FF; Cyrillic
 --0500..052F; Cyrillic Supplement
 --0530..058F; Armenian
 --0590..05FF; Hebrew
 --0600..06FF; Arabic
 --0700..074F; Syriac
 --0780..07BF; Thaana
 --...
 
 --
 -- algo de traduction inspiré du document "RFC 2044 - UTF-8, a transformation format of Unicode 
 -- and ISO 10646" qui décrit le format UTF-8 --
 --
 -- Extait du document :
 --
 --   UCS-4 range (hex.)    UTF-8 octet sequence (binary)
 --   0000 0000-0000 007F   0xxxxxxx
 --   0000 0080-0000 07FF   110xxxxx 10xxxxxx
 --   0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
 
 --   Encoding from UCS-4 to UTF-8 proceeds as follows:
 --
 --   1) Determine the number of octets required from the character value
 --      and the first column of the table above.
 --
 --   2) Prepare the high-order bits of the octets as per the second column of the table.
 --
 --   3) Fill in the bits marked x from the bits of the character value,
 --      starting from the lower-order bits of the character value and
 --      putting them first in the last octet of the sequence, then the
 --      next to last, etc. until all x bits are filled in.
 --
 
 n= length(la_chaine)
 i=1
 
 repeat while(i<=n)
   le_car = la_chaine.char[i]
   le_code = chartonum(le_car)
 
   -- filtre pour certains caractères spéciaux dont le code n'est pas correct / unicode
   le_code = FilterLingoChar(le_code, true)
 
   if(le_code<128)then
     -- plage 0000 0000-0000 007F (ASCII)
     -- on laisse comme ça !
   else
     if(le_code<256)then
       -- plage 0000 0080-0000 00FF (Latin-1)
       -- il faut construire 110xxxxx 10xxxxxx
 
       -- on fait un cache sur les 2 bits de poids fort de "le_code"
       -- 192 -> 11000000
       le_code_1 = bitor(192, bitand(le_code, 192)/64)
 
       -- on fait un cache sur les 6 bits de poids faible de "le_code"
       -- 128 -> 10000000
       -- 63  -> 00111111
       le_code_2 = bitor(128, bitand(le_code, 63))
 
       put numtochar(le_code_1) & numtochar(le_code_2) into la_chaine.char[i]
 
       i=i+1 -- décalage supplémentaire car on met 2 caractères à la place d'un seul
 
       n=n+1 -- la taille de la chaine augmente donc d'un caractère
 
     else
       if(le_code<65535)then -- pas vraiment nécessaire mais bon...
         -- plage 0000 0800-0000 FFFF
         -- il faut construire 1110xxxx 10xxxxxx 10xxxxxx
 
         -- on fait un cache sur les 4 bits de poids fort de "le_code"
         -- 224 -> 11100000
         -- 61440 -> 11110000 00000000
         le_code_1 = bitor(224, bitand(le_code, 61440)/4096)
 
         -- on fait un cache sur les 6 bits de poids moyen de "le_code"
         -- 128 -> 10000000
         -- 4032  -> 00001111 11000000
         le_code_2 = bitor(128, bitand(le_code, 4032)/64)
 
         -- on fait un cache sur les 6 bits de poids faible de "le_code"
         -- 128 -> 10000000
         -- 63  -> 00111111
         le_code_3 = bitor(128, bitand(le_code, 63))
 
         put numtochar(le_code_1) & numtochar(le_code_2) & numtochar(le_code_3) into la_chaine.char[i]
 
         i=i+2 -- décalage supplémentaire car on met 3 caractères à la place d'un seul
 
         n=n+2 -- la taille de la chaine augmente donc de 2 caractères
 
       end if
     end if
   end if
 
   i=i+1 -- caractère suivant
 end repeat
 
 return la_chaine
end
 
on UTF8StrToLingoStr la_chaine
 
 -- voir doc de la fonction LingoStrToUTF8Str
 
 sSave = la_chaine
 n = length(la_chaine)
 i=1
 
 repeat while(i<=n)
 
   le_car = la_chaine.char[i]
   le_code = chartonum(le_car)
 
   -- 128 -> 1000 0000
   if(bitand(le_code, 128)=128)then
 
     -- 192 -> 1100 0000
     if(bitand(le_code, 192)=192)then
 
       -- 224 -> 1110 0000
       if(bitand(le_code, 224)=224)then
 
         -- 240 -> 1111 0000
         if(bitand(le_code, 240)=240)then
           -- erreur, caractère de code trop élevé pour stocker en lingo
           -- on ne fait rien
         else
           -- séquence triple de type 1110xxxx 10xxxxxx 10xxxxxx
           if(i<n-1)then
             le_code_2 = chartonum(la_chaine.char[i+1])
             le_code_3 = chartonum(la_chaine.char[i+2])
 
             if(bitand(le_code_2, 128)=128)and(bitand(le_code_2,64)=0)and(bitand(le_code_3, 128)=128)and \
             (bitand(le_code_3, 64)=0)then
 
               -- on récupère les bits utiles (les x)
               -- 63 -> 0011 1111
               -- 15 -> 0000 1111
               le_code = bitand(le_code_3, 63) + 64*bitand(le_code_2, 63) + 4096*bitand(le_code, 15)
 
               -- filtre pour certains caractères spéciaux dont le code n'est pas correct / unicode
 
               le_code = FilterLingoChar(le_code, false)
 
               put numtochar(le_code) into la_chaine.char[i..i+2]
               n=n-2 -- la taille de la chaine diminue donc de 2 caractères
 
             else
               -- erreur : il n'est pas possible de tomber sur un debut de
               -- séquence sans suite du type 10xxxxxx 10xxxxxx
 
               return sSave
             end if
           else
             -- erreur : il n'est pas possible de tomber sur un debut de
             -- sequence sans suite du type 10xxxxxx 10xxxxxx
 
             return sSave
           end if
         end if
 
       else
         -- sequence double de type 110xxxxx 10xxxxxx
 
         if(i<n)then
           le_code_2 = chartonum(la_chaine.char[i+1])
 
           if(bitand(le_code_2, 128)=128)and(bitand(le_code_2, 64)=0)then
             -- on récupère les bits utiles (les x)
             -- 63 -> 0011 1111
             -- 31 -> 0001 1111
 
             le_code = bitand(le_code_2, 63) + 64*bitand(le_code, 31)
 
             -- filtre pour certains caractères spéciaux dont le code n'est
             -- pas correct / unicode
 
             le_code = FilterLingoChar(le_code, false)
 
             put numtochar(le_code) into la_chaine.char[i..i+1]
 
             n=n-1 -- la taille de la chaine diminue donc d'un caractère
 
           else
             -- erreur : il n'est pas possible de tomber sur un debut de
             -- sequence sans suite du type 10xxxxxx
 
             return sSave
           end if
 
         else
 
           -- erreur : il n'est pas possible de tomber sur un debut de
           -- sequence sans suite du type 10xxxxxx
 
           return sSave
 
         end if
       end if
 
     else
 
       -- erreur : il n'est pas possible de tomber sur un debut de sequence
       -- avec un debut 10xxxxxx
 
       return sSave
     end if
 
   else
 
     -- sequence unique
     -- rien à faire !
   end if
 
   i=i+1 -- caractère suivant
 
 end repeat
 
 return la_chaine
 
end
 
 
on FilterLingoChar le_code, bFromLingo
 
 -- filtre pour certains caractères spéciaux dont le code n'est pas correct / unicode
 
 if(bFromLingo)then
 
   -- traduction de lingo vers Unicode
 
   liste1 = [128, 130, 131,132, 133, 134, 135, 136,137, 138,139,
 
140,142,145, 146, 147, 148, 149, 150, 151, 152,153, 154,155, 156,158,159]
 
   le_num = liste1.getone(le_code)
 
   if(le_num>0)then
 
     liste2 = [8364,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,381,8216,8217,8220,
     8221,8226,8211,8212,732,8482,353,8250,339,382,376]
 
     le_code = liste2[le_num]
   end if
 
 else
   -- traduction d'Unicode vers Lingo
   liste1 = [8364,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,381,8216,8217,8220,
   8221,8226,8211,8212,732,8482,353,8250,339,382,376]
 
   le_num = liste1.getone(le_code)
 
   if(le_num>0)then
 
     liste2 = [128, 130, 131,132, 133, 134, 135, 136,137, 138,139,
     140,142,145, 146, 147, 148, 149, 150, 151, 152,153, 154,155, 156,158,159]
 
     le_code = liste2[le_num]
 
   end if
 end if
 
   return le_code
 
end