Journal Esod mumixam !

Posté par  (site web personnel) . Licence CC By‑SA.
41
4
déc.
2014

À toutes fins utiles, j'ai rédigé un petit traducteur pour la zorglangue. Un traducteur de et vers la zorglangue, puisque, comme le ROT13, le codage et le décodage se font avec la même seule opération.

Subtilités de ce traducteur :

  • il est écrit en Python 3 (et n'utilise que des modules standard) ;
  • il laisse la ponctuation en place ;
  • il met les majuscules où il faut, même pour des caractères hors ASCII.

Exemples :

$ echo 'Dose maximum !' | zorglang
Esod mumixam !
echo 'Dose maximum !' | zorglang | zorglang
Dose maximum !

Voilà, c'est tout, ça devrait même marcher pour des langues qui s'écrivent de droite à gauche puisque cette subtilité est indépendante du flux de caractères. Eviv Bulgroz !

Ah non, j'oubliais. Le code :

#! /usr/bin/python3

import io
import re
import sys

word_re = re.compile(r'\b\w+\b')

def zorglang(text):
    with io.StringIO() as buf:
        last_index = 0
        for match in word_re.finditer(text):
            buf.write(text[last_index:match.start()])
            word = match.group()
            for i in range(len(word)):
                if word[i].isupper():
                    buf.write(word[-1 - i].upper())
                elif word[i].islower():
                    buf.write(word[-1 - i].lower())
                else:
                    buf.write(word[-1 - i])
            last_index = match.end()
        buf.write(text[last_index:])
        return buf.getvalue()

if __name__ == '__main__':
    for line in sys.stdin:
        print(zorglang(line), end='')
  • # M'enfin

    Posté par  . Évalué à 3.

    M'enfin, Gaston va enfin pouvoir lire Spirou

    ⚓ À g'Auch TOUTE! http://afdgauch.online.fr

    • [^] # Re: M'enfin

      Posté par  (site web personnel) . Évalué à 10.

      Mais si Gaston lit Spirou, est-ce qu’il écrit lui aussi au courrier des lecteurs ?

      ce commentaire est sous licence cc by 4 et précédentes

      • [^] # Re: M'enfin

        Posté par  (site web personnel) . Évalué à 10.

        En tout cas il est bien placé pour savoir ce qu'il adviendra de la réponse.

        Courrier en retard 1
        Courrier en retard 2
        Courrier en retard 3

        Paix et prospérité à l'âme de Franquin.

        kentoc'h mervel eget bezan saotred

  • # En php?

    Posté par  (site web personnel) . Évalué à -6.

    Je me demande si le php n'est pas plus simple:
    Découper la phrase avec explode() puis inverser les lettres de chaque mot avec strrev.
    Je ne code pas beaucoup mais amha cela doit pouvoir se régler en 5 lignes.

    • [^] # Re: En php?

      Posté par  (site web personnel) . Évalué à 10.

      La même approche serait tout aussi simple en Python, mais le problème, c'est que :

      • la ponctuation ne serait pas au bon endroit ;
      • les majuscules ne seraient pas au bon endroit.

      Ça donnerait ça :

      $ echo 'Dose maximum !' | zorglang-simpliste
      esoD mumixam !
      $ echo 'Zorglub, au secours !' | zorglang-simpliste
      ,bulgroZ ua sruoces !
      • [^] # Re: En php?

        Posté par  (site web personnel) . Évalué à 10.

        M'apprendra à balancer un truc en deux minutes du boulot….

        • [^] # Re: En php?

          Posté par  . Évalué à 10.

          Il faut prendre plus le temps quand tu est au boulot.

  • # Emroné \!

    Posté par  . Évalué à 3.

    À dnauq iulec ruop eriudart al eugnal Fpmuorths ?

  • # Sans expression rationnelle

    Posté par  . Évalué à 1.

    Une variante utilisant seulement les outils de manipulations de chaînes

    #! /usr/bin/python3
    
    import sys
    
    def reverse_word(word):
        reversed_word = list(word)[::-1]
        if word[0].isupper():
            reversed_word[0] = reversed_word[0].upper()
            reversed_word[-1] = reversed_word[-1].lower()
        return ''.join(reversed_word)
    
    def zorglang(text):
        return ' '.join(
            [reverse_word(word) for word in text.split()]
        )
    
    for line in sys.stdin:
        print(zorglang(line), end='')
    • [^] # Re: Sans expression rationnelle

      Posté par  (site web personnel) . Évalué à 4. Dernière modification le 04 décembre 2014 à 17:46.

      Ce n'est pas équivalent, la ponctuation se retrouve mal placée :

      $ echo 'Zorglub, au secours !' | zorglang-simpliste
      ,bulgroz ua sruoces !$

      Et le retour à la ligne final est mangé, au passage (d'où l'invite de commande $ que j'ai mis sur la ligne de résultat, dans mon example).

      • [^] # Re: Sans expression rationnelle

        Posté par  . Évalué à -1.

        Yep, mais cette piste est quand meme plus lisible. Dans le même esprit, on peut en tout cas simplifier pas mal la fonction de départ par:

        def zorglang(text):
            last_index = 0 
            res = ""  
            for match in word_re.finditer(text):
                res += text[last_index:match.start()]
                word = match.group()
                wasup = word[0].isupper()
                word = ''.join(reversed(word))
                if wasup:
                    word = word.capitalize()
                res += word
                last_index = match.end()
            res += text[last_index:]
            return res
        • [^] # Re: Sans expression rationnelle

          Posté par  (site web personnel) . Évalué à 10.

          Effectivement, remplacer le StringIO par une simple chaîne permet de tuer les performances en forçant une copie à chaque opération, et n'effectuer le test de capitalisation que pour la première lettre permet de ne plus transcrire correctement les mots à capitalisation interne tels que LinuxFr.org.

          C'est un peu plus simple, oui. Et moins bien.

          • [^] # Re: Sans expression rationnelle

            Posté par  . Évalué à 3.

            et ça donne quoi LinuxFr.org en zorgland? (je ne suis pas sûr de la place du point et de la majuscule "interne")

            • [^] # Re: Sans expression rationnelle

              Posté par  (site web personnel) . Évalué à 5.

              RfxunIl.gro

              (le point sépare deux mots ; les lettres sont capitalisées à la même place que dans les mots d'origine, en tout cas c'est mon interprétation, Franquin n'ayant pas exploré ce genre de subtilité)

              • [^] # Re: Sans expression rationnelle

                Posté par  (site web personnel) . Évalué à 7.

                Je connais très peu l'univers Spirou, mais au vu des règles que tu as exposées dans ce journal et les commentaires, j'ai le sentiment que l'esprit serait plutôt que ça donne "XunilRf.gro".

                Pour tenter d'expliquer, l'idée générale que je vois est de garder la « structure » , par exemple s'il y a une majuscule en début de phrase, elle doit l'être au début du résultat et pas à la fin, de même pour la ponctuation, et les mots sont dans le même ordre, et de n'inverser les lettres qu'au sein d'un seul mot délimité par cette structure à la fois.

                Et pour moi cette construction (accoler deux mots en capitalisant leur première lettre) relève de la structuration. D'où mon sentiment.

                • [^] # Re: Sans expression rationnelle

                  Posté par  (site web personnel) . Évalué à 3.

                  Peut-être, l'ennui étant que ce cas de se présentant pas à ma connaissance dans les albums de Spirou et Fantasio de Franquin, on ne pourra jamais le savoir. Et, par ailleurs, la détection de mot dans les expressions rationnelles considère LinuxFr comme un seul mot, donc je m'y suis tenu. En outre, il est plus facile de lire RfxunIl.gro que XunilRf.gr, même si la capitalisation interne n'y est plus que cosmétique.

                  • [^] # Re: Sans expression rationnelle

                    Posté par  (site web personnel) . Évalué à 3.

                    En outre, il est plus facile de lire RfxunIl.gro que XunilRf.gr, même si la capitalisation interne n'y est plus que cosmétique.

                    Si j'ai bien compris le peu que j'ai lu sur Zorglub-truc-machin-chose, c'est plutôt un argument contre ta solution, ça, non ? ;-)

  • # as allways

    Posté par  . Évalué à -7.

    ça se termine en concours de celui qui à la plus grosse. da linux french page devient déprimant.

    • [^] # Re: as allways

      Posté par  (site web personnel) . Évalué à 1.

      euh, c'est le rot13 qui te fait dire cela ? rot24 comme Rocco_Siffredi c'est l'inverse de 42 on va dire… l'alphabet français est de 26 lettres

    • [^] # Re: as allways

      Posté par  . Évalué à 10.

      Cela s'écrit "as hallways" ou en bon français "comme dans les couloirs"

      Désolé …

    • [^] # Re: as allways

      Posté par  (site web personnel) . Évalué à 4.

      Personnellement, c'est, je trouve, la partie la plus intéressante du journal.
      Mais t'as le droit de préférer un journal avec que des commentaires "wow, super ! Rien à redire, c'est l'algo parfait !".

  • # et en perl

    Posté par  . Évalué à 7.

    plop

    je rajoute du vide pour éviter le décalage de l'avatar

    #!/bin/perl
    use strict;
    while( <STDIN>){
        while ( m/(\w+)(\W*)/g) {
            my ($mot, $sep ) = ($1, $2);
            for(  my $i = 0 ; $i <= (length $mot)  ; $i++){
                if(  substr( $mot,$i,1) =~ /[A-Z]/  )  { 
                    print uc( substr( $mot, -1-$i, 1 )); 
                }
                else { 
                    print lc( substr( $mot, -1-$i, 1 )) ;
                }
            }
            print "${sep}";
        }
    }

    Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: et en perl

      Posté par  . Évalué à 4.

      sur un système utf-8 il peut être utile de faire l'une des action suivante

      • export PERL_UNICODE="" $ echo Hé Y a un caractère accentué | zorg.pl
      • utiliser le switch -CIO $ echo Hé Y a un caractère accentué | perl -C zorg.pl
      • ajouter use open qw(:std :utf8); au niveau des use ;) $ echo Hé Y a un caractère accentué | zorg.pl

      Voila, j'ajouterai qu'en cas de caractères spéciaux avant le premier mot, ils sont bouffés; je poste donc une version améliorée qui marche avec de la ponctuation avant :

      !/usr/bin/perl
      use strict;
      use open qw(:std :utf8);
      while( <STDIN>){
         while ( m/(\w*)(\W*)/g) {
           my ($mot, $sep ) = ($1, $2);
           for(  my $i = 0 ; $i <= (length $mot)  ; $i++){
             if(  substr( $mot,$i,1) =~ /[A-Z]/  )  {
               print uc( substr( $mot, -1-$i, 1 ));
             }
             else {
               print lc( substr( $mot, -1-$i, 1 )) ;
             }
          }
          print "${sep}";
        }
      }

      $> echo '!!! ya mêMe des accents en plein milieu !!!'| ./zorg.pl
      !!! ay emÊm sed stnecca ne nielp ueilim !!!
      $>

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: et en perl

        Posté par  . Évalué à 4.

        et encore une correction :)

        remplacer [A-Z] par \p{upper}

        Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: et en perl

        Posté par  . Évalué à 3.

        Pareil (si je dis pas de bêtises), mais sans boucle :)

        #!/usr/bin/perl
        use strict;
        use warnings;
        use open qw(:std :utf8);
        
        while (<>) {
            s|(\p{Alphabetic})(\p{Alphabetic}*)|
                my ($first, $rest) = ($1,$2);
                ($first =~ /\p{upper}/)
                    ? (ucfirst reverse $rest) . (lc $first)
                    : (reverse $rest) . $first
            |xeg;
            print;
        }
        • [^] # Re: et en perl

          Posté par  . Évalué à 3.

          presque mais
          $>echo '!Eviv BuLgrozé!!' | zorg2.pl
          !Vive ÉzorgLub!!
          $>

          On a un changement des majuscules interne au mot, ce n'est donc pas équivalent au code initial; ensuite je me demande si on peut pas de faire a coup de regex récursive ;)
          (t)ru(C) => C(r)(u)t => Curt, à rechercher du coté de la recherche des palindromes (du point de vu de la logique)

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: et en perl

            Posté par  . Évalué à 2.

            On a un changement des majuscules interne au mot, ce n'est donc pas équivalent au code initial

            Pas faux, j'avais pas pensé que les majuscules à l'intérieur des mots étaient à prendre en compte de cette façon.

          • [^] # Re: et en perl

            Posté par  . Évalué à 2.

            ensuite je me demande si on peut pas de faire a coup de regex récursive ;)
            (t)ru(C) => C(r)(u)t => Curt, à rechercher du coté de la recherche des palindromes (du point de vu de la logique)

            Je vois pas trop comment on pourrait s'en sortir avec des regexps récursives, car elles servent uniquement à matcher. Peut-être en utilisant des blocs ?{...} pour insérer du code dans la regexp. Par contre, on peut s'en sortir en faisant une fonction récursive :

            #!/usr/bin/perl
            use strict;
            use warnings;
            use open qw(:std :utf8);
            
            sub zorglangize {
                my $text = shift;
                if ($text =~ /(\p{Alphabetic})(\p{Alphabetic}*)(\p{Alphabetic})/) {
                    my ($first, $middle, $last) = ($1, $2, $3); 
                    return (($first =~ /\p{upper}/) ? (uc $last) : (lc $last))
                        . zorglangize($middle)
                        . (($last =~ /\p{upper}/) ? (uc $first) : (lc $first));
                } else {
                    return $text;
                }
            }
            
            while (<>) {
                s/(\p{Alphabetic}+)/zorglangize($1)/xeg;
                print;
            }

            mais c'est un peu tordu… et probablement moins efficace que d'utiliser substr et des indices. Mais c'est marrant quand même :)

            • [^] # Re: et en perl

              Posté par  . Évalué à 4.

              et probablement moins efficace que d'utiliser substr et des indices

              Bon, test sur un roman de plus de trois cent pages, j'obtiens :

              0m0.55s real     0m0.53s user     0m0.01s system (version récursive)
              0m0.55s real     0m0.54s user     0m0.02s system (version python du journal)
              0m0.47s real     0m0.45s user     0m0.02s system (ta version)
              

              Comme quoi, ça change pas grand chose, et dans tous les cas, c'est clair que les langages de script sont pas fait pour travailler sur du texte caractère à caractère.

  • # Plus simple

    Posté par  (site web personnel) . Évalué à 7.

    >,[<++++[->--------<]>[>,--------------------------------]<[>[-]++++[-<++++++++>]<.<]>[-]<++++[->++++++++<]>.[-],]
    
    • [^] # Re: Plus simple

      Posté par  . Évalué à 2.

      J'allais la demander !

      Du coup, je change mon fusil d'épaule : quelqu'un pour du befunge, ou j'ai le temps d'y réfléchir demain ?

      Matricule 23415

    • [^] # Re: Plus simple

      Posté par  . Évalué à 3.

      Zorglub, Au secours!
      ,bulgroZ uA

      Il y a un souci quelque part !

  • # elituni

    Posté par  (site web personnel) . Évalué à 6.

    cnod eriassecén

    kentoc'h mervel eget bezan saotred

  • # Merci, ô grand merci ...

    Posté par  . Évalué à 1.

    … d'avoir enfin utilisé Python dans un contexte qui lui va particulièrement bien. C'est d'ailleurs le genre de truc pour lequel on devrait utiliser Python, et ne garder les autres trucs sérieux que pour des langages dignes de ce nom (Ruby étant l'un des meilleurs).

    • [^] # Re: Merci, ô grand merci ...

      Posté par  . Évalué à 7. Dernière modification le 05 décembre 2014 à 11:22.

      Tu te trompes. C’est justement parce qu’il est aussi possible d’utiliser Python à des fin burelesques qu’il surpasse Ruby : lui (Python) au moins n’a pas une pierre coincée dans l’oignon.

      • [^] # Re: Merci, ô grand merci ...

        Posté par  . Évalué à 3.

        Tu te trompes. C’est justement parce qu’il est aussi possible d’utiliser Python à des fin burelesques qu’il surpasse Ruby : lui (Python) au moins n’a pas une pierre coincée dans l’oignon.

        Après le monkey patching de Ruby, je crois que le burlesque n'a plus de limites que ce soit pour Ruby ou pour Python…

        "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

    • [^] # Re: Merci, ô grand merci ...

      Posté par  . Évalué à 3.

      je regrette son programme ne respecte pas la norme python, il manque une citation :P

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: Merci, ô grand merci ...

      Posté par  . Évalué à 4.

      Trop gros, passera pas…

  • # Parce que j'essaye de progresser en bash

    Posté par  . Évalué à 5.

    sentence=$*
    for word in $sentence
    do
    
    if [[ "$word" =~ ^.*([!?.,:;])+.*$ ]];then
            punct=${BASH_REMATCH[1]};
            new_word="${word/$punct/}"
            the_word=`echo $new_word | rev`
            result="$result $the_word$punct"
    else
            the_word=`echo $word | rev`
            result="$result $the_word"
    fi
    done
    echo $result

    ./zorg "la phrase à reverser, une bonne phrase qui tue."
    al esarhp à resrever, enu ennob esarhp iuq eut.

    • [^] # Re: Parce que j'essaye de progresser en bash

      Posté par  . Évalué à 5.

      Il y a un problème au niveau des majuscule et des la gestion de la ponctuation ;)

      $>./zorg.sh '!!!Plop!?!'
      !?!polP!!!

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Parce que j'essaye de progresser en bash

        Posté par  . Évalué à 3.

        ahoui….

        petit scarabée devra progresser encore.

      • [^] # Re: Parce que j'essaye de progresser en bash

        Posté par  . Évalué à 2.

        Amélioration des majuscules, mais bon la ponctuation est toujours dans les choux, enfin… dans une certaine mesure.

        sentence=$*
        for word in $sentence
        do
        
        punct=""
        if [[ "$word" =~ ^.*([!?.,:;])+.*$ ]];then
                punct=${BASH_REMATCH[1]};
        fi
        new_word="${word/$punct/}"
        
        pl=${new_word:0:1};
        if [[ ${pl} == [a-z] ]] & [[ `printf '%o' "'${pl}"` < 133  ]];then
                new_word=${new_word,}
                the_word=`echo $new_word | rev`
                the_word=${the_word^}
        else
                the_word=`echo $new_word | rev`
        fi
        
                result="$result $the_word$punct"
        done
        echo $result

        herve@DreamMachine:~$ ./zorg "La phrase à reverser, Une bonne phrase Qui tue."
        Al esarhp à resrever, Enu ennob esarhp Iuq eut.

  • # Haskell

    Posté par  . Évalué à 10.

    import Data.Char
    import Data.List
    import System.Environment
    
    zorglangue :: String -> String
    zorglangue = concatMap capReverse . splitWords
    
    w :: Char -> Bool
    w x = isAlphaNum x || x == '_' 
    
    splitWords :: String -> [String]
    splitWords = groupBy (\a -> \b -> w a == w b)
    
    capReverse :: String -> String
    capReverse xs | not (all w xs) = xs 
    capReverse xs = map cap $ zip (map (\x -> if isUpper x then toUpper else toLower) xs) (reverse xs)
        where cap (f, c) = f c
    
    
    main :: IO()
    main = getContents >>= putStrLn . unlines . map zorglangue . lines
    $ echo "Zorglub, Au secours!" | ./zorglangue
    Bulgroz, Ua sruoces!

    J'ai passé un bon vendredi…

    • [^] # Re: Haskell

      Posté par  . Évalué à 2.

      Pourquoi faire du faux "currying"?

      (\a -> \b -> w a == w b) est la même chose que (\a b -> w a == w b).

      Ruby est le résultat d'un gamin qui apprend le Java, puis jette un œil à Perl et se dit « je peux le réparer! »

      • [^] # Re: Haskell

        Posté par  . Évalué à 3. Dernière modification le 07 décembre 2014 à 12:40.

        Qui est la même chose que :

        (==) `on` w

        qui est la même chose que :

        (==) `on` ((||) <$> isAlphaNum <*> (=='_'))

        Huhuhu, le Haskell, qu'est-ce qu'on se marre.

        EDIT: Oh, j'avais pas remarqué, très joli emploi du zip !

        • [^] # Re: Haskell

          Posté par  . Évalué à 1.

          ah oui merci pour le on. justement je me souvenais avoir vu ça, mais impossible de retrouver comment faire…

          • [^] # Re: Haskell

            Posté par  . Évalué à 3.

            Dans le même genre, tu peux remplacer ça getContents >>= putStrLn . unlines . map zorglangue . lines par ça interact $ unlines . map zorglangue . lines.

            Et ça map cap $ zip l1 l2 where cap (f, c) = f c par ça zipWith ($) l1 l2.

            Et enfin (mais là je suis pas sûr sûr, en tout cas les types matchent), ça concatMap capReverse . splitWords par ça capReverse <=< splitWords.

            • [^] # Re: Haskell

              Posté par  . Évalué à 2.

              '<=<' je connaissais pas.
              j'ai lu "programming in haskell", j'ai presque fini "learn yourself a haskell", et j'ai toujours l'impression de ne pas trop maitriser le haskell…

              alors qu'à l'époque, pour python il m'a suffit d'un tutorial…

              • [^] # Re: Haskell

                Posté par  . Évalué à 7.

                Ce que je trouve, c'est qu'avec haskell, il y a beaucoup de choses simples dans d'autres langages qui sont enrobées de choses compliquées, et pas forcément faciles à retenir au début. Et puis certaines choses qu'on estime de base, pour lesquelles on a des syntaxes spéciales dans d'autres langages (tableaux, chaînes de caractères et tables de hachages) ne sont pas plus pratiques à utiliser que des choses moins courantes. En fait, la seule structure de base vraiment pratique à utiliser en Haskell, c'est les listes chaînées.

                Mais le plus gênant, c'est quand tu crois que tu commences à connaître le langage et que tu tombes sur du code qui utilise des Lens, Arrows ou autre et tu t'aperçois qu'en fait, non :)

  • # blague

    Posté par  . Évalué à 1.

    référence inside

    et grotesque se dit euqsetorg je suppose?

    fin de ma blague, celui qui trouve la référence gagne un bon point

    • [^] # Re: blague

      Posté par  . Évalué à 4.

      si personne ne trouve avant vendredi prochain tu nous donneras la réponse ?

      • [^] # Re: blague

        Posté par  . Évalué à 2.

        rhalala, bon c'est dans "l'horloger de la comète" de Tome et Janry. Je ne peux donner la page pour l'instant la BD est toujours chez mes parents qui ne sont pas à côté.

  • # Let's get Groovy, Baby!

    Posté par  (site web personnel) . Évalué à 6.

    Moi aussi je saute des lignes pour éviter l'avatar.

    Ou alors je pourrais vous mettre la version Java.

    Nan j'déconne.

    #!/usr/bin/env groovy
    
    def original = args ? args[0] : System.in.available() ? System.in.text : ""
    
    print original.split( "\\b" ).collect {
        if ( it =~ /\w+/ ) {
            def result = ""
            def chars = it.toCharArray()
            chars.eachWithIndex { c, i ->
                result += c.isLowerCase() ? chars[-i - 1].toLowerCase() : chars[-i - 1].toUpperCase()
            }
            result
        } else {
            it
        }
    }.join()
  • # Avec du poil aux pattes

    Posté par  . Évalué à 9.

    Une version en x86_64, pour Linux. À assembler avec FASM.

    Pour l'ASCII étendu, suit l'ISO 8859-15 (aka Latin-9), et donc pas l'UTF-8. Limites en dur pour la longueur de la ligne et des mots.

    format ELF64 executable 3
    
    entry _start
    
    TAILLE_BUF=256
    TAILLE_MOT=64
    
    segment readable executable
    
    _start:
        XOR RAX, RAX        ; 0 (sys_read)
        XOR RDI, RDI        ; 0 (stdin)
        MOV RSI, bufin      ; adresse du tampon d'entrée
        MOV RDX, TAILLE_BUF ; taille du tampon
        SYSCALL             ; lecture
    
        MOV [longueur], RAX  ; nombre d'octets lus
    
    
        XOR RDI, RDI
    teste_nouveau_caractere:
    ; on teste le nouveau caractère
        CALL nature_caractere
        CMP AL, 0
        JNE nouveau_mot
    ; ponctuation et divers : on l'écrit tel quel
        MOV [bufout+RDI], DL
        JMP suivant
    
    nouveau_mot:
    ; lettre : début d'un nouveau mot
        XOR RBX, RBX        ; compteur des caractères du mot
        MOV RSI, RDI        ; mémorise la position (offset) du début du mot
    ; on recherche la fin de ce nouveau mot en enregistrant pour chaque lettre son type
    continue_mot:
        MOV [mot+RBX], DL
        MOV [type_car+RBX], AL
        MOV [casse_car+RBX], AH
        INC RDI
        CALL nature_caractere
        CMP AL, 0
        JE fin_mot
        INC RBX
        JMP continue_mot
    fin_mot:
        push RDX
    
        XOR RCX, RCX
    inverse_mot:
    ; quelle casse faut-il ?
        MOV AL, [casse_car+RCX] ; casse du caractère d'origine
        CMP AL, 0
        JNE minuscule
    ; majuscule
        MOV AL, [casse_car+RBX] ; casse du nouveau caractère
        CMP AL, 0
        JNE monter_casse
    ; déjà en majuscule, il faut juste copier
        MOV AL, [bufin+RSI+RBX]
        MOV [bufout+RSI+RCX], AL
        JMP fin_corps_boucle_mot
    monter_casse:
        MOV AL, [type_car+RBX]
        CMP AL, 1
        JNE pas_min_std
        MOV AL, [mot+RBX]
        ADD AL, "A"
        MOV [bufout+RSI+RCX], AL
        JMP fin_corps_boucle_mot
    pas_min_std:
        CMP AL, 2
        JNE pas_min_acc
        MOV AL, [mot+RBX]
        ADD AL, 0xC0  ; "À"
        MOV [bufout+RSI+RCX], AL
        JMP fin_corps_boucle_mot
    pas_min_acc: ; e dans l'o
        mov [bufout+RSI+RCX], 0xBC ; "Œ"
        JMP fin_corps_boucle_mot
    minuscule:
        MOV AL, [casse_car+RBX] ; casse du nouveau caractère
        CMP AL, 1
        JNE baisser_casse
    ; déjà en minuscule, il faut juste copier
        MOV AL, [bufin+RSI+RBX]
        MOV [bufout+RSI+RCX], AL
        JMP fin_corps_boucle_mot
    baisser_casse:
        MOV AL, [type_car+RBX]
        CMP AL, 1
        JNE pas_maj_std
        MOV AL, [mot+RBX]
        ADD AL, "a"
        MOV [bufout+RSI+RCX], AL
        JMP fin_corps_boucle_mot
    pas_maj_std:
        CMP AL, 2
        JNE pas_maj_acc
        MOV AL, [mot+RBX]
        ADD AL, 0xE0  ; "à"
        MOV [bufout+RSI+RCX], AL
        JMP fin_corps_boucle_mot
    pas_maj_acc: ; E dans l'O
        mov [bufout+RSI+RCX], 0xBD  ; "œ"
    fin_corps_boucle_mot:
        INC RCX
        DEC RBX
        JNS inverse_mot
    ; on copie le dernier caractère que l'on vient de trouver
        pop RDX
        MOV [bufout+RDI], DL
    
    suivant:
        INC RDI
        CMP RDI, [longueur]
        JL teste_nouveau_caractere
    
        MOV RDI, 1          ; 1 (stdout)
        MOV RSI, bufout     ; adresse du message à afficher
        MOV RDX, [longueur] ; nombre d'octets à écrire
        MOV RAX, 1          ; 1 (sys_write)
        SYSCALL             ; écriture
    
    ; Exit
        MOV RDI, 0          ; status de sortie = SUCCESS
        MOV RAX, 60         ; 60 (sys_exit)
        SYSCALL             ; exécution de la sortie
    
    
    ;; === ROUTINE nature_caractere ===
    ;; entrée :
    ;;   rdi : index caractère dans le tampon bufin
    ;; sorties :
    ;;   al  : type du caractère :
    ;;         0 : ponctuation, divers
    ;;         1 : lettre standard
    ;;         2 : lettre accentuée
    ;;         3 : e dans l'o
    ;;   ah  : 0 : majuscule
    ;;         1 : minuscule
    ;;   dl  : rang du caractère dans le type
    ;; ===
    
    nature_caractere:
        MOV DL, [bufin+RDI]
    test_majuscule:
        CMP DL, "A"
        JB autres
        CMP DL, "Z"
        JA test_minuscule
    ; majuscule standard
        MOV AL, 1
        MOV AH, 0
        SUB DL, "A"
        RET
    
    test_minuscule: 
        CMP DL, "a"
        JB autres
        CMP DL, "z"
        JA test_edanlo
    ; minuscule standard
        MOV AL, 1
        MOV AH, 1
        SUB DL, "a"
        RET
    
    test_edanlo:
        CMP DL, 0xBC  ; "Œ"
        JB autres
        JNE test_edanlo_min
    ; e dans l'o majuscule
        MOV AL, 3
        MOV AH, 0
        SUB DL, 0xBC  ; "Œ"
        RET
    test_edanlo_min:
        CMP DL, 0xBD  ; "œ"
        JA test_majuscule_accentuee
    ; e dans l'o minuscule
        MOV AL, 3
        MOV AH, 1
        SUB DL, 0xBC  ; "Œ"
        RET
    
    test_majuscule_accentuee:
        CMP DL, 0xC0  ; "À"
        JB autres
        CMP DL, 0xDD  ; "Y'"
        JA test_minuscule_accentuee
    ; majuscule accentuee
        MOV AL, 2
        MOV AH, 0
        SUB DL, 0xC0
        RET
    
    test_minuscule_accentuee:
        CMP DL, 0xE0  ; "à"
        JB autres
        CMP DL, 0xFD  ; "y'"
        JA autres
    ; minuscule accentuee
        MOV AL, 2
        MOV AH, 1
        SUB DL, 0xE0
        RET
    
    autres: 
        MOV AX, 0
        RET
    ;; === FIN nature_caractere ===
    
    
    segment readable writeable
    
        bufin       RB TAILLE_BUF
        bufout      RB TAILLE_BUF
        mot         RB TAILLE_MOT
        type_car    RB TAILLE_MOT
        casse_car   RB TAILLE_MOT
        longueur    DQ 0

    Pas spécialement propre (je dois écrire en moyenne 50 lignes d'assembleur par an…), ni documenté, ni optimisé (mais vus les langages d'urbains épilés présentés dans la plupart des autres propositions, ce programme (binaire de 1364 octets) devrait avoir fini son exécution avant que les autres n'aient fini leur chargement en mémoire). Ne gère pas pas correctement les signes « multiplication » et « division » (pas envie de m'embêter pour ce cas particulier « intelligemment » placé au beau milieu des majuscules accentuées).

    • [^] # Re: Avec du poil aux pattes

      Posté par  (site web personnel) . Évalué à 3.

      vus les langages d'urbains épilés présentés dans la plupart des autres propositions, ce programme (binaire de 1364 octets) devrait avoir fini son exécution avant que les autres n'aient fini leur chargement en mémoire

      Ah bah peut-être (encore que tu sais pas ce qu'un compilo / une VM malins peuvent faire !), mais nous au moins :

      • on est pas limité à un seul processeur
      • on gère l'UTF-8 parce qu'on est plus en 1992 et les chinois aussi ont internet
      • on met pas de limite de taille arbitraire parce que 140 characters 640kB should be enough for everyone
      • on a pas (ou alors pas fait exprès et on corrige :-p) un truc qui fait-le-job-mais-en-fait-pas-pour-X-et-Y-t'as-qu'à-t'en-passer

      Alors au choix hein… :-P

      • [^] # Re: Avec du poil aux pattes

        Posté par  . Évalué à 5.

        on est pas limité à un seul processeur

        Vu que le script original est en Python…

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Avec du poil aux pattes

          Posté par  (site web personnel) . Évalué à 4.

          J'ai mis du temps à comprendre ta remarque. Alors elle est juste (et pas que pour la version python, les autres ne me semblent pas non plus utiliser de multithreading), mais on ne parle pas de la même chose :) Je parlais du fait que son assembleur x86_64 ne doit pas trop bien marcher sur d'autres types de processeurs alors que le python, le perl, le groovy… pas de souci. Mais c'est vrai que j'aurais du dire "un seul type de processeur".

      • [^] # Re: Avec du poil aux pattes

        Posté par  . Évalué à 5.

        tu sais pas ce qu'un compilo / une VM malins peuvent faire !

        Mouais, c'est quelque chose que l'on entend répété ad nauseam depuis des années, mais en pratique il est rare qu'ils produisent un code plus performant qu'un premier jet bêtement codé à la main. Et de toutes manières, vu qu'en général on passe son temps à appeler des fonctions assez génériques qui ne sont donc pas optimisées pour le cas que l'on utilise, il n'y a pas grand chose d'optimisable par le compilateur…

        on gère l'UTF-8 parce qu'on est plus en 1992 et les chinois aussi ont internet

        OK, mais on le gère comment ? Faudrait se mettre d'accord sur ce qu'on veut avant de commencer à le gérer, sinon, on gère l'UTF-8 en entrée mais en produisant une sortie au petit bonheur la chance. Par exemple, dans le programme Python d'origine, le "\w" de la regexp ne va pas forcément donner les résultats que l'on attend. Avec les chiffres, par exemple, pour "Vol_714", on pourrait raisonnablement attendre "Lov_714" (comportement de mon programme) ou "Lov_417" comme résultat. Eh bien non, parce que le "\w" compte les chiffres et les "_" comme des caractères de mot, ça va donner "417_lov". Ah non, tiens, en plus ça donne "417_loV", une « erreur » supplémentaire :-) puisque les chiffres n'ont pas de casse et que dans ce cas le programme recopie les caractères tels qu'ils sont entrés).

        Quant au Chinois, tu as choisi un bon exemple des emmerdements dans lesquels on est plongé par la complexité et la richesse d'Unicode si on veut le gérer dans son intégralité : dans un texte chinois, il n'y a pas de mots discernables et il n'y a pas de majuscules. Bim, les 2 principales spécification de notre zorglub sautent. Que fait-on ? On inverse tout le bloc d'idéogrammes entre 2 ponctuations, comme le programme d'origine le fait ? Ou pas ? Et surtout quel sens cela a-t-il de rentrer du chinois dans ce programme ?

        on met pas de limite de taille arbitraire parce que 140 characters 640kB should be enough for everyone

        Ben dans la langue de Franquin, le mot le plus long ayant 25 caractères, avec 64 on should be tranquille. Sinon, on rachètera un caractère supplémentaire pour écrire « 128 » à la place :-)

        on a pas (ou alors pas fait exprès et on corrige :-p)

        Oui, je constate que c'est le mode de développement actuel. « Allez, cette fonction a un bon nom, je vais l'utiliser ; on verra bien ce que ça donne : avec un peu de bol, ça marche. » … « hop c'est bon, j'ai testé avec un exemple, ça roule. Ouais, non lire la spécification de la fonction, ce n'est pas la peine puisque ça marche pour l'instant. On verra bien si quelqu'un se plaint » …
        NB : j'ai bien conscience que dans les programmes présentés ici, il ne s'agit pas d'un logiciel critique ou d'un soft facturé 200 000 € à un malheureux pige^ Wclient, mais d'un petit jeu, donc ces reproches(?) ne leur sont pas destinés mais puisque je vois qu'on est d'humeur taquine… :-)

        un truc qui fait-le-job-mais-en-fait-pas-pour-X-et-Y-t'as-qu'à-t'en-passer

        Ben… au moins dans le truc que j'ai proposé, les caractéristiques et les limites sont assez clairement mises en avant.
        Si on respecte ces règles, le comportement devrait être fiable1.

        Si on prend le programme d'origine, pour les même données d'entrées, si on l'exécute dans un environnement différent (changement des locales) => BOUM. Alors il vaut peut-être mieux savoir ce qui est supporté et ce qui ne l'est pas par le programme et s'y tenir plutôt que d'avoir un comportement non prévu ou un crash.


        1. là, logiquement, comme quand on fait une remarque sur l'orthographe, je ne doute pas que quelqu'un va me faire remarquer que j'ai oublier de traiter/spécifier un cas particulier :-) Ce que je veux dire, c'est que j'ai essayé d'une part d'être conscient des limites de ma version et de les mentionner et d'autre part de ne traiter qu'un type d'entrée restreint à ce qui fait sens, plutôt que de faire un truc qui est censé tout traiter sans limites, mais qui le fait mal ou de manière inattendue. Et le coup de la non-gestion assumée des signes « multiplier » et « diviser », c'est un geste politique de protestation contre la faute de goût d'avoir collé ces deux signes en plein milieu des majuscules accentuées :-). Sinon, c'est juste 2 fois 2 instructions à rajouter pour les gérer correctement. 

        • [^] # Re: Avec du poil aux pattes

          Posté par  . Évalué à 4.

          tu sais pas ce qu'un compilo / une VM malins peuvent faire !

          Mouais, c'est quelque chose que l'on entend répété ad nauseam depuis des années, mais en pratique il est rare qu'ils produisent un code plus performant qu'un premier jet bêtement codé à la main.

          Chic, chic, un troll ! Donc euh, mon boulot a été, pendant un moment, d'optimiser des codes scientifiques (qui souvent sont bien plus faciles à optimiser pour un compilateur que des codes plus traditionnels). Je n'ai presque jamais eu à recourir à l'écriture en ASM, mais par contre savoir le lire était important :

          1. Il fallait pouvoir reconnaître un code peu optimisé par le compilateur (alors qu'on pouvait faire mieux)
          2. Il fallait quand même pouvoir écrire 2-3 trucs à la main dans certains cas précis
          3. La plupart des cas où j'avais besoin de faire du fine tuning, je passais par les intrinsics de gcc/llvm/icc (par exemple, si on veut utiliser les instructions MMX/SSE/AVX sur x86/x64), ce qui était quand même 'achement plus simple pour obtenir des diagnostics d'erreur quand je me plantais.
          4. La plupart du temps, le compilateur est bien plus malin que le programmeur.

          Concernant mon dernier point : au final, plutôt qu'écrire en ASM, je finissais par savoir comment exprimer mes programmes sous une forme que le compilateur savait optimiser. Souvent, ça passe par la « débilisation » du code : si on essaie d'être trop intelligent, le compilateur voit un tas de code compliqué, et laisse tomber. Si au contraire on écrit le code de la façon la plus simple possible, souvent le compilo comprend l'idiome, et trouve des choses intelligentes à faire. Il y a bien entendu des exceptions :

          • Si on essaie d'optimiser pour les caches, il faut souvent recourir à des techniques de « blocking » ou « tiling », mais là encore on peut s'arranger pour ne pas se mettre en travers du compilateur (par exemple, on met la partie à optimiser du code dans une fonction à part, et ainsi on l'isole du nid de boucle qui l'entoure).
          • Il y a des fois où le compilateur se plante réellement dans la génération du code, mais là encore, faire de « l'assembleur en C » permet le plus souvent de le remettre dans le droit chemin.

          Sur certaines architectures c'est relativement faux : par exemple sur Itanium, tout un tas de mécanismes super cool concernant la prédication des branches, la spéculation de contrôle ou de données, etc., n'étaient tout simplement pas accessible à moins de faire de l'assembleur (gcc est dans les choux niveau optim sur ia64, et icc interdit l'utilisation d'assembleur inline — mais il y a des intrinsics pour certains trucs).

          Bref. J'en profite pour lier vers ce blog qui propose un quiz à propos de différentes optimisations que le compilateur peut effectuer.

          Et de toutes manières, vu qu'en général on passe son temps à appeler des fonctions assez génériques qui ne sont donc pas optimisées pour le cas que l'on utilise, il n'y a pas grand chose d'optimisable par le compilateur…

          Ça par contre je suis relativement d'accord. Je n'ai pas été regarder, mais j'aimerais bien savoir s'il existe des fonctions de la libc qui ont des variantes, du genre (code non testé, y'a sans doute des bugs) :

          #ifdef __HAS_AVX__ 
          #define memcpyAVX memcpy
          #elif __HAS_SSE2__
          #define memcpySSE2 memcpy
          #elif //...
          //...
          #endif
          
          void *memcpySSE2(void *restrict s1, const void *restrict s2, size_t n) {
              if (n < sizeof(_m128d)) { // size to copy is less than 8 chars
                  char *dst = (char*) s1, *src = (char*) s2;
                  while ( n-- )
                      *dst++ = *src++;
              } else if ( is_aligned16(s1) && is_aligned16(s2) ) { // aligned on 16B
                  _m128d src; // or _m128i with _mm_load_si128/_mm_store_si128, doesn't really matter here...
                  size_t i;
                  for (i = 0; i < n-8; i += 8) {
                      src = _mm_load_ps ( s2 + i );
                      _mm_store_ps ( s1 + i, src ); // copy, 8 chars at a time
                  }
                  for (; i < n; ++i)  // epilogue
                      *((char*)s1+i) = *((char*)s2+i);
              } else { // unaligned accesses
                  _m128d src; // or _m128i with _mm_loadu_si128/_mm_storeu_si128, doesn't really matter here...
                  size_t i;
                  for (i = 0; i < n-8; i += 8) {
                      src = _mm_loadu_ps ( s2 + i );
                      _mm_storeu_ps ( s1 + i, src ); // copy, 8 chars at a time
                  }
                  for (; i < n; ++i)  // epilogue
                      *((char*)s1+i) = *((char*)s2+i);
              }
          }

          NB: avec icc (et en supposant que mon code ne soit pas complètement rempli de bugs, ce qui est très possible), les boucles vont être déroulées, entre 2 et 6 fois, pour tirer avantage des 16 registres SSE. Pour tirer avantage des cas intermédiaires, icc va générer des variantes qui vont complètement dérouler les cas du genre N=8, N=16, N=32, etc. Je ne crois pas que gcc fasse cela aussi systématiquement, mais il commence aussi à être bon pour ce qui est de la vectorisation.

Suivre le flux des commentaires

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