Journal Jouons avec Unicode: Tchars, un Dchars pour Troff

Posté par (page perso) . Licence CC by-sa
22
31
oct.
2013

Sommaire

Vous n'avez pas manqué de suivre ici les aventures de Dchars, de notre ami Xavier Faure. Dchars permet entre autres de transformer une suite codifiée de caractères ascii en caractères utf8 complexes. Par exemple, il transforme le beta-code en grec polytonique. Dans ce journal, vous découvrirez l'histoire de Tchars, le sosie de Dchars.

Tchars, un Dchars pour Troff

Ayant justement besoin d'écrire quelques mots en grec polytonique dans ma thèse, je me suis penché dans les sources de Dchars, pour voir si je ne pouvais pas le modifier pour en faire un pré-processeur pour troff, mon logiciel de formatage de texte, et l'ajouter aux logiciels du projet Utroff. Malheureusement, Dchars est écrit en python, et je rechignais à ajouter python aux dépendances d'Utroff.

Plutôt que de modifier Dchars, je me suis donc lancé dans une ré-écriture en C des fonctionnalités de Dchars qui m'intéressaient. Et cela m'a beaucoup amusé, puisque ça a été l'occasion pour moi de comprendre un peu Unicode, l'utf8, l'hexadécimal et les opérations binaires. Il me semble que cela vous amusera beaucoup aussi, alors puisqu'il me faut publier quelque part ce savoir encore frais pour le jour prochain ou je l'oublierai, entrons dans les entrailles de Tchars.

Tchars, qui signifie Troff|Translate characters, a beaucoup moins de fonctionnalités que Dchars. Mais il fait bien son travail qui consiste à transformer une forme simplifiée de beta-code en grec polytonique. C'est un programme finalement assez simple, écrit en 600 lignes de C, dont 300 ne font que définir les correspondances entre le beta-code et le code unicode.

Du Beta-code à l'unicode

Cette liste de correspondances est d'ailleurs générique car générée automatiquement. La fondation unicode fournit en effet un fichier UnicodeData.txt qui liste l'ensemble des caractères unicode, et indique entre autres leur nom ainsi que leur code hexadécimal. J'ai donc commencé par écrire un script shell appuyé sur sed qui filtre ce fichier pour en extraire les caractères grecs (repérés par le nom GREEK), effacer les lignes inutiles, substituer les noms complets par leur correspondance en beta code (s/SMALL LETTER ALPHA/a/g;), substituer le nom des tons par leur correspondance en beta code (s/DIALYTIKA/+/g;), mettre le tout en forme, et trier la liste pour l'utiliser dans une structure en C. Au final, j'ai une longue liste de 300 lignes de correspondances entre code ascii et valeur hexadécimale, de la forme :

struct runelist
{
    char *tag;
    unsigned hexa;
};

runelist alphabeta[] =
{
        /* This list must be sorted */
    {"A", 0x0391,},
    {"A&", 0x1FB9,},
    {"A'", 0x1FB8,},
    {"A(", 0x1F09,},
    {"A(/", 0x1F0D,},
    {"A(=", 0x1F0F,},
    {"A(\\", 0x1F0B,},
    {"A)", 0x1F08,},
    {"A)/", 0x1F0C,},
    {"A)=", 0x1F0E,},
    {"A)\\", 0x1F0A,},
    {"A/", 0x0386,},
    {"A/", 0x1FBB,},
    {"A\\", 0x1FBA,},
}

De l'unicode à l'utf8 : généralités

Sur cette base, il a été possible d'écrire le code C. L'ensemble est assez banal : une fonction lit le texte en entrée, repère les lignes où il y a du code à translittérer, et pour chaque suite de caractères en beta-code, un binary search recherche le code hexadécimal correspondant. On pourrait en rester là, car Troff peut transformer lui-même ce code hexadécimal en un caractère utf8. Mais lorsque j'ai compris qu'écrire une fonction qui fasse cette transformation n'était pas hors de ma portée, je me suis jeté à l'eau.

Pour comprendre la dite fonction, il faut savoir qu'un caractère utf8 est encodé sur 1, 2, 3, 4, 5 ou 6 bytes, selon la valeur de son code hexadécimal :

First           Last            Bytes
U+0000          U+007F          1
U+0080          U+07FF          2
U+0800          U+FFFF          3
U+10000         U+1FFFFF        4
U+200000        U+3FFFFFF       5
U+4000000       U+7FFFFFFF      6

Le premier byte d'un caractère utf8 indique combien de bytes composent le caractère. Chacun des bytes suivant commence par les bits 10, suivant cette table :

Byte 1          Byte 2          Byte 3          Byte 4          Byte 5          Byte 6
0xxxxxxx
110xxxxx        10xxxxxx
1110xxxx        10xxxxxx        10xxxxxx
11110xxx        10xxxxxx        10xxxxxx        10xxxxxx
111110xx        10xxxxxx        10xxxxxx        10xxxxxx        10xxxxxx
1111110x        10xxxxxx        10xxxxxx        10xxxxxx        10xxxxxx        10xxxxxx

La table hexadécimale nous explique comment écrire chacun de ces bytes sous forme hexadécimale :

0       0000    8       1000
1       0001    9       1001
2       0010    A       1010
3       0011    B       1011
4       0100    C       1100
5       0101    D       1101
6       0110    E       1110
7       0111    F       1111

1100 0000 = C0
1110 0000 = E0
1111 0000 = F0
1111 1000 = F8
1111 1100 = FC
1000 0000 = 80

De l'unicode à l'utf8 : implémentation

Ainsi, pour chaque code unicode indiqué en hexadécimal, il faut commencer par repérer de combien de bytes est composé le caractère. Pour cela, il suffit de quelques tests :

void
hexatochars(unsigned hexa)
{

        if (hexa < 0x0080) {
                /* 1 byte */
        }
        else if (hexa < 0x800) {
                /* 2 bytes */
        }
        else if (hexa < 0x10000) {
                /* 3 bytes */
        }
        else if (hexa < 0x200000) {
                /* 4 bytes */
        }
        else if (hexa < 0x4000000) {
                /* 5 bytes */
        }
        else if (hexa < 0x7FFFFFFF) {
                /* 6 bytes */
        }
        else {
                /* hors unicode */
        }
}

Sitot le nombre de bytes à construire connu, il n'y a plus qu'à construire ces bytes un par un, par des opérations binaires. L'opération générale consiste à décaler, mettre à zero, combler ces zeros. Prenons l'exemple d'un caractère unicode à deux bytes. Il aura la forme : 110xxxxx 10xxxxxx. On commence par compter le nombre de petits x : il y en a 11, ce qui signifie que le code hexadécimal du caractère unicode a donc 11 bits : xxxxxxxxxxx. Pour composer le premier byte, on a besoin des 5 premiers bits. On décale donc tout vers la droite, pour en mettre 6 dehors et obtenir 000xxxxx :

hexa >> 6

Il faut en outre combler les trois premiers zeros par les trois premiers bits du premier byte, pour obtenir 110xxxxx. On utilise l'opérateur binaire | et le byte 11000000 (soit 0xc0 en hexadecimal) :

((hexa >> 6) | 0xc0)

Pour composer le second byte, on a besoin des 6 derniers bits du code hexadecimal. On ne conserve donc que les les 6 derniers avec l'opérateur binaire & et le byte 0011 1111 (soit 0x3F) :

hexa & 0x3F

Puis on impose les deux premiers bits au second byte, avec l'opérateur binaire | et le byte 10000000 (soit 0x80) :

((hexa & 0x3F) | 0x80)

Petit à petit, on obtient la fonction suivante :

void
hexatochars(unsigned hexa)
{
        char a=0, b=0, c=0, d=0, e=0, f=0;

        /*
        ** From U+000 to U+007F
        ** Utf8 is coded on 1 byte of the form :
        ** 0xxxxxxx
        */
        if (hexa<0x0080) {
                a = hexa; // 0xxxxxxx
        }
        /*
        ** From U+0080 to U+07FF
        ** Utf8 is coded on 2 bytes of the form :
        ** 110xxxxx 10xxxxxx
        */
        else if (hexa < 0x800) {
                a = ((hexa >> 6) | 0xC0); // 110xxxxx
                b = ((hexa & 0x3F) | 0x80); // 10xxxxxx
        }
        /*
        ** From U+0800 to U+FFFF
        ** Utf8 is coded on 3 bytes of the form :
        ** 1110xxxx 10xxxxxx 10xxxxxx
        */
        else if (hexa < 0x10000) {
                a = ((hexa >> 12) | 0xE0); // 1110xxxx
                b = (( (hexa >> 6) & 0x3F) | 0x80);
                c = ((hexa & 0x3F) | 0x80);
        }
        /*
        ** From U+10000 to U+1FFFFF
        ** Utf8 is coded on 4 bytes of the form :
        ** 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        */
        else if (hexa < 0x200000) {
                a = ((hexa >> 18) | 0xF0); // 11110xxx
                b = (((hexa >> 12) & 0x3F) | 0x80);
                c = (((hexa >> 6) & 0x3F) | 0x80);
                d = ((hexa & 0x3F) | 0x80);
        }
        /*
        ** From U+200000 to U+3FFFFFF
        ** Utf8 is coded on 5 bytes of the form :
        ** 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        */
        else if (hexa < 0x4000000) {
                a = ((hexa >> 24) | 0xF8); // 111110xx
                b = (((hexa >> 18) & 0x3F) | 0x80);
                c = (((hexa >> 12) & 0x3F) | 0x80);
                d = (((hexa >> 6) & 0x3F) | 0x80);
                e = ((hexa & 0x3F) | 0x80);
        }
        /*
        ** From U+4000000 to U+7FFFFFFF
        ** Utf8 is coded on 6 bytes of the form :
        ** 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        */
        else if (hexa < 0x7FFFFFFF) {
                a = ((hexa >> 30) | 0xFC); // 1111110x
                b = (((hexa >> 24) & 0x3F) | 0x80);
                c = (((hexa >> 18) & 0x3F) | 0x80);
                d = (((hexa >> 12) & 0x3F) | 0x80);
                e = (((hexa >> 6) & 0x3F) | 0x80);
                f = ((hexa & 0x3F) | 0x80);
        }
        /*
        ** Out of unicode range
        */
        else {
                fprintf(stderr,
                "tchars : [%x] is not in unicode range, file xxx, line %d\n",
                hexa, l);
        }

        printf("%c%c%c%c%c%c", a, b, c, d, e, f);
}

Conclusion

Il existe probablement une bibliothèque standard du C qui fait cette transformation: j'ai cherché un peu, mais ne l'ai pas trouvée… Si vous la connaissez, ou si, simplement, vous avez des choses à redire sur le code ci-dessus, utilisez les commentaires, je serais enchanté d'en apprendre un peu plus.

Quoi qu'il en soit, Dchars a maintenant un compagnon, et Utroff intègre dorénavant un interpréteur de beta-code facilement extensible à d'autres langages.

Pour le reste, vous pouvez consulter, modifier, publier tchars (licence BSD à deux clauses) ou tout simplement le tester en téléchargeant l'archive d'Utroff

  • # Meilleur traduction vers l'utf8

    Posté par . Évalué à 5.

    On peut faire un peut mieux que répéter les shift & masques dans ta fonction hexatochars() :

    unsigned int bits = hexa;
    if (hexa >= (1<<26)) {
        a |= 1<<2;
        f = (bits & 0x3f) | 0x80;
        bits >>= 6;
    }
    if (hexa >= (1<<21)) {
        a |= 1<<3;
        e = (bits & 0x3f) | 0x80;
        bits >>= 6;
    }
    if (hexa >= (1<<16)) {
        a |= 1<<4;
        d = (bits & 0x3f) | 0x80;
        bits >>= 6;
    }
    if (hexa >= (1<<11)) {
        a |= 1<<5;
        c = (bits & 0x3f) | 0x80;
        bits >>= 6;
    }
    if (hexa >= (1<<7)) {
        a |= (1<<6) | (1<<7);
        b = (bits & 0x3f) | 0x80;
        bits >>= 6;
    }
    a |= bits;
    

    J'ai écrit les constantes différemment car je trouve que ça permet de mieux se rendre compte que les intervalles proposés par ce standard encodent 7, 4, 5, 5, 5 et 5 bits chacun, pour un total 31 bits pour un “code point”. En plus, avec le fait qu'on shift toujours de 6 bits, ça m'avait embrouillé sur le calcul, mais en fait ça marche exactement comme ça car chaque octet qui s'ajoute vient rétrécir d'un bit la place qu'on a dans le premier (sauf au premier ajout, où on perd 2 bits car on ne peut pas prendre le préfixe « réservé » 0b10xxxxxx)

    • [^] # Re: Meilleur traduction vers l'utf8

      Posté par (page perso) . Évalué à 3.

      C'est beaucoup plus élégant effectivement. Tellement élégant que je ne comprends d'ailleurs pas encore bien comment ça marche: tout ça n'est pas familier pour moi, et il me faudra encore un peu de temps pour bien comprendre ton algorithme.

      • [^] # Re: Meilleur traduction vers l'utf8

        Posté par . Évalué à 4.

        Moi non plus je vois pas très bien comment ça marche mais remplacer des else if par des if à la queue-leu-leu c'est uxamifiant.

        • [^] # Re: Meilleur traduction vers l'utf8

          Posté par . Évalué à 5.

          Son code confirme le fameux proverbe qu'on apprend en maternelle de programmation : « L'optimisation est la route de toutes les villes » :/

          « Je vous présente les moines Shaolin : ils recherchent la Tranquillité de l'Esprit et la Paix de l'Âme à travers le Meurtre à Main Nue »

    • [^] # Re: Meilleur traduction vers l'utf8

      Posté par . Évalué à 10. Dernière modification le 31/10/13 à 18:38.

      « On peut faire un peut mieux que répéter les shift & masques dans ta fonction hexatochars()»

      Ton mieux consiste à éviter les répétitions de décalages & masques qui sont très efficients à l'exécution par une multiplication de tests conditionnels & d'écritures mémoire beaucoup moins efficients : c'est déjà à mon humble avis d'amateur une erreur certaine. Si en plus tu le fais en complexifiant le codepath, mais surtout les lisibilité & clarté du code, c'est à mon humble avis d'expert une horreur qu'on ne peut tolérer même en plein fête ancestrale d'Halloween :/

      Analysons le cas le plus courant : en UTF-8 dans les langues occidentales, la majorité des caractères sont ASCII et avec son code, voilà ce qui est exécuté est :

      if (hexa<0x0080) {
          a = hexa; // 0xxxxxxx
      }
      

      Soit un test conditionnel, aucun masque et une écriture. Avec ton code, tout est exécuté : du premier test au dernier en passant par tous les décalages & masques et les écritures que contient ton code : 5 tests conditionnels, 15 écritures et un nombre décalages & masques trop volumineux pour être répertorié ici en si peu de temps.

      Tu vas maintenant me dire que si l'entrée est du klingon plutonion tel qu'on le parle en Sibérie du Nord, avec un majorité de caractères dans la "zone haute", ton code est meilleur et qu'à l'évidence, j'ai triché. Ok, puisque tu le prends comme ça, analysons aussi ce cas-là. Avec son code, tous les tests échouent sauf le dernier bloc qui est exécuté : on a 5 tests échouants, 1 succès et 6 écritures. Alors que dans ton cas, tous les tests passent - ce qui semble mieux mais comme derrière on a presque 3 fois plus d'écriture et à vue d'oeil autant voire plus de shifts & masks, c'est un véritable échec.

      Au final, je pense que tu as fournis le pire exemple de "simplification" qui soit, tant au niveau 1) de la lisibilité, 2) du codepath, 3) de l'exécution aini que 4) de l'atteinte du but que tu veux viser :( En fait si ton code donne l'impression d'être plus simple en raison de sa brièveté, c'est une pure illusion d'optique : si tu étudies tous les codepathes possibles & imaginables, et cela quelque soit l'entrée, dans ton cas on a toujours plus de tests, d'écritures et de décalages que dans le sien ! Malgré tout cela, ton commentaire est hypertinenté à l'heure où je te répond.

      À défaut d'être un bon prestataire digital, je te conseille donc de te reconvertir en prestidigitateur.

      « Je vous présente les moines Shaolin : ils recherchent la Tranquillité de l'Esprit et la Paix de l'Âme à travers le Meurtre à Main Nue »

      • [^] # Commentaire supprimé

        Posté par . Évalué à 3. Dernière modification le 31/10/13 à 19:46.

        Ce commentaire a été supprimé par l'équipe de modération.

      • [^] # Re: Meilleur traduction vers l'utf8

        Posté par . Évalué à 2.

        Avec ton code, tout est exécuté : du premier test au dernier en passant par tous les décalages & masques et les écritures que contient ton code : 5 tests conditionnels, 15 écritures et un nombre décalages & masques trop volumineux pour être répertorié ici en si peu de temps.

        Petite correction : oui pour les 5 tests, mais une seule affectation, la dernière, tout les tests échouant. L'ensemble des shifts & masks ne sont exécutés que pour la zone la plus « haute ».

        Au final, je pense que tu as fournis le pire exemple de "simplification" qui soit, tant au niveau 1) de la lisibilité,

        Effectivement, au départ je me disais que ça serait « mieux » niveau lisibilité car il n'y a pas de répétition, mais ça fait un peu étrange quand même ; je comprends le côté uxamifiant.

        2) du codepath,

        Pas tant que ça, même s'il y a effectivement beaucoup de branchements.

        3) de l'exécution

        Idem.

        aini que 4) de l'atteinte du but que tu veux viser

        Ah, là, je n'ai jamais exprimé de but dans ce commentaire ;-) j'avais juste une intuition qu'on pouvait faire « mieux », et je voyais des relations entre les différents préfixes et les décalages, j'ai sorti ce bout de code qui exprimait « mieux » le cœur du problème, je trouve. C'est vrai qu'au final il est un peu étrange. Note qu'on pourrait même en faire une boucle, mais pour la « clareté » je l'ai déroulée.

        • [^] # Re: Meilleur traduction vers l'utf8

          Posté par (page perso) . Évalué à 4.

          Ce que j'aime bien dans ton algorithme, c'est qu'il nous dit quelque chose de la structure d'utf8. Je suis d'ailleurs curieux de voir la version boucle.

          • [^] # Re: Meilleur traduction vers l'utf8

            Posté par . Évalué à 1.

            J'ai retravaillé le code pour qu'il soit « plus clair », et j'ai minimisé l'information « arbitraire » pour ne plus avoir que la taille des codes pour chaque octet. Le résultat est également donné sous forme de tableau plutôt que des variables a à f, où les octets sont à lire de i à 0. Ce qui donne :

            unsigned int bits = hexa;
            unsigned char code_size[] = [7, 4, 5, 5, 5, 5];
            unsigned char result[] = [0, 0, 0, 0, 0, 0];
            size_t i = 0;
            
            for (unsigned int total_code_size = 1<<code_size[0];
                    hexa >= total_code_size;
                    i++, total_code_size <<= code_size[i]) {
                result[i] |= 0x80; // utile seulement à la première itération
                result[i+1] = (result[i]>>1) | 0x80;
                result[i] |= bits & 0x3f;
                bits >>= 6;
            }
            result[i] |= bits;
            

            Ça doit sûrement paraître uxamifiant à certains, et ce code n'a pas été testé, mais je pense qu'il est bon (aux casts près, je me rends compte en relisant). Ça n'est pas le top niveau lisibilité, mais niveau quantité d'information donnée et calculée ça doit s'approcher du minimum.

  • # Bibliothèques

    Posté par (page perso) . Évalué à 4.

    Il existe effectivement déjà des bibliothèques pour faire ce que tu veux en C.
    Les deux premières qui pourraient fonctionner sont iconv et icu (uconv).
    Dans les deux cas, tu peux partir d'UCS-4 (≃UTF-32) ou wchar et arriver en UTF-8.
    En plus en bonus tu as la possibilité de fonctionner avec autre chose que de l'UTF-8 en sortie.

    • [^] # Re: Bibliothèques

      Posté par (page perso) . Évalué à 3.

      Si tu as un exemple, je suis preneur, car j'ai quand même cherché du côté de wchar, et suite à ton commentaire j'ai regardé la page de manuel d'iconv(3), et je t'avoue que je ne vois toujours pas bien quelles fonctions dans ces bibliothèques acceptent l'hexadecimal d'unicode en entrée.

      • [^] # Re: Bibliothèques

        Posté par (page perso) . Évalué à 4.

        Voilà un petit exemple vite-fait avec iconv, qui prend de l'UCS-4 ("hexadécimal") en entrée et qui sort de l'UTF-8.

        #include <stdio.h>
        #include <stdint.h>
        #include <stdlib.h>
        #include <errno.h>
        #include <iconv.h>
        #include <endian.h>
        
        int main(int argc, char **argv)
        {
            uint32_t ucode[] = {
                htobe32(0x0391), /* A   */
                htobe32(0x1FB9), /* A&  */
                htobe32(0x1FB8), /* A'  */
                htobe32(0x1F09), /* A(  */
                htobe32(0x1F0D), /* A(/ */
            };
            char buf[32] = "";
        
            iconv_t cd;
            char *inbuf, *outbuf;
            size_t insize, outsize, status, outlen, i;
        
            inbuf = (char*)ucode;
            insize = sizeof(ucode);
            outbuf = buf;
            outsize = sizeof(buf);
            outlen = 0;
        
            cd = iconv_open("UTF-8", "UCS-4BE");
            do
            {
                printf("in: %zu bytes left\n", insize);
                printf("out: %zu bytes left\n", outsize);
                status = iconv(cd, &inbuf, &insize, &outbuf, &outsize);
                if(status == (size_t)-1)
                {
                    perror("iconv");
                    exit(1);
                }
            } while(insize > 0 && outsize > 0);
            iconv_close(cd);
        
            outlen = sizeof(buf) - outsize;
            printf("\n");
            printf("Output utf-8: \"%.*s\"\n", (int)outlen, buf);
            printf("\n");
            printf("%zu bytes:\n", outlen);
            for(i=0 ; i<outlen ; i++)
            {
                printf("out[%02zu] = 0x%X\n", i, (uint8_t)buf[i]);
            }
        
            return 0;
        }
        
        • [^] # Re: Bibliothèques

          Posté par (page perso) . Évalué à 2.

          Merci pour l'exemple (et pour l'UCS-4, dont j'ignorais l'existence).

          Un jour, il faudra bien que j'étudie un peu les bibliothèques du C…

  • # Code similaire pour l'UTF-16

    Posté par . Évalué à 3.

    J'avais eu le même problème il y a quelque temps, donc j'avais codé ce même genre de fonctions, à la diffrence que la conversion ne se fait qu'entre l'UTF-16 et l'UTF-8, et de l'UTF-8 vers le Latin 1 (ISO-8859-1).

    https://www.assembla.com/code/dittox/subversion/nodes/34/trunk/parcittox/dittox/dittox.cpp

    Chercher à partir de la fonction conv_utf16_to_8. Le code est sous domaine publique.

    • [^] # Re: Code similaire pour l'UTF-16

      Posté par (page perso) . Évalué à 3.

      Trouvé:

      /* 3 bytes UTF-8 */
      
           *dest++ = 0xE0 | (*src >> 12);
           *dest++ = 0x80 | ((*src >> 6) & 0x3F);
           *dest++ = 0x80 | (*src++ & 0x3F);
      

      C'est marrant ces petites nuances qui font la différence…

  • # félicitations !

    Posté par (page perso) . Évalué à 7.

    Bonsoir, je suis l'auteur de DChars et j'écris ces lignes le sourire aux lèvres : quel bonheur que de voir d'autres que moi libérer leur code et le faire savoir de façon aussi intéressante. C'est vraiment le libre au sommet de sa forme : efficacité du code (je parle de TChars pour le coup) et courtoisie maximale. Longue vie à ce projet !

    Si je puis être utile en quoi que ce soit à Sygne, qu'il me le fasse savoir : j'ai beaucoup apprécié cette dépêche !

    Trust the Python !

    • [^] # Re: félicitations !

      Posté par (page perso) . Évalué à 5. Dernière modification le 03/11/13 à 11:15.

      Salut !

      C'est ta dépêche sur Dchars qui m'avait appris l'existence du beta-code, que j'ignorais jusqu'alors. J'ai ensuite pris beaucoup de plaisir à lire ton code et ta doc, tous deux très soignés.

      Puisque tu es là, et que tu m'y invites, permets-moi ces quelques questions :

      Comment ce fait-il que tu aies tant de projets tournant autour des langues, en particulier anciennes (Phoseg, Dchars, Logotheras, Phokaia) ? Est-ce un hobby, un besoin professionnel ou associatif ?

      Aurais-tu entendu parler d'une méthode de translittération simple du coréen (hangul) ?

      • [^] # Re: félicitations !

        Posté par (page perso) . Évalué à 4.

        Bonjour Sygne,
        je suis enseignant de "Lettres Classiques" (français, latin, grec) au collège et cela fait longtemps que je veux contribuer au libre pour faciliter la transmission des langues que j'enseigne et que j'aime. La situation actuelle est pour moi comparable à celle de la Renaissance : les technologies évoluent et seuls les contenus qui s'adaptent aux nouvelles technologies survivront. J'essaye, très modestement, de participer à ce grand mouvement.

        Merci pour ta remarque sur la qualité de la documentation dans mon code : ayant jusqu'à peu codé seul, j'avais besoin d'aide pour être capable de relire mon code; écrire de la doc' me permet surtout de réutiliser mon code, sinon, je n'y comprends rapidement plus rien.

        Quant au hangul, désolé, je n'y connais rien. Mais tout est relatif, si je peux t'aider sur un projet concernant le coréen, peut-être puis-je t'aider ?

        Trust the Python !

        • [^] # Re: félicitations !

          Posté par (page perso) . Évalué à 4.

          je suis enseignant de "Lettres Classiques"

          Tout s'explique ! On devrait former un club de lettrés développeurs !

          Quant au coréen, je me demandais si tu n'avais pas travaillé dessus pour Dchars. C'est une écriture alphabétique, et il existe une translittération officielle vers l'alphabet occidental, mais celle-ci est fortement marquée par la phonétique, et prend en compte des changements de prononciation qui ne s'écrivent pourtant pas. Et de fait cette translittération officielle me semble difficile à implémenter, outre qu'elle est perturbante pour moi qui ai un peu l'habitude du coréen écrit.

          J'ai cherché après d'autres potentielles translittérations, mais sans résultat, d'où ma question.

  • # Correspondance béta-code -> hexa

    Posté par . Évalué à 4.

    Je trouve dommage d'avoir codé en dur la correspondance. En utilisant un fichier, il me semble qu'il aurait pu facilement devenir un traducteur beta code générique (de ce que je vois sur wikipedia le beta code ne sert pas qu'au grec ancien). Le traitement d'un fichier serait trop long face au traitement des fichiers ? Ou pense-tu qu'il vaudrait mieux coder en dur l'ensemble du beta code (ça doit être limité et stable) ?

    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Correspondance béta-code -> hexa

      Posté par (page perso) . Évalué à 4.

      Je trouve dommage d'avoir codé en dur la correspondance.

      C'est vrai que ce serait pratique que ce soit configurable, surtout s'il s'agit d'ajouter des méthodes de translittérations vers d'autres langages.

      Le traitement d'un fichier ne serait pas trop long : il suffirait de produire à la volée la même structure que celle qui est ici codée en dur, ce qui ne coûte pas grand chose, d'autant plus qu'il n'y a aucune raison de courir après les performances. Il faut juste voir si cela reste pertinent s'il y a de nombreuses méthodes de translittérations. Et il faudrait aussi que je sois un peu plus confiant en ma capacité à gérer la mémoire en C pour me lancer dans l'aventure. Mais ce serait une bonne occasion de m'entraîner.

      Quant au beta-code, c'est une norme un peu bizarre: Elle est en vérité très longue (cf. deuxième liens externe de wikipédia) et de nombreux caractères sont codés par un numéro, ce qui fait qu'il n'y a pas grand intérêt à préférer la valeur beta-code plutôt que la valeur unicode pour ces caractères ; et même pour le grec ancien, les majuscules sont indiquées par "*A" et les minuscules par "A", ce qui n'est pas des plus pratique.

      Tchars s'inspire de beta-code plus qu'il ne le respecte, et Dchars, s'il sait en interpréter correctement une partie, propose d'autres méthodes de translittérations plus intuitives.

  • # 33% d'optimisation

    Posté par . Évalué à 3.

    J'avoue avoir eu une petite suée en lisant qu'UTF-8 se codait sur jusqu'à 6 octets. Heureusement, la page wikipédia m'a vite confirmé dans mes certitudes (faut pas m'faire des peurs comme ça):

    The original specification covered numbers up to 31 bits (the original limit of the Universal Character Set). In November 2003 UTF-8 was restricted by RFC 3629 to end at U+10FFFF, in order to match the constraints of the UTF-16 character encoding. This removed all 5- and 6-byte sequences, and about half of the 4-byte sequences.

    Tu peux donc te passer du traitement des 2 derniers octets, rien n'étant codé sur plus de 4 octets.

    Sinon, je suis bien content de voir que le projet Utroff continue à se développer. :)

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.