Valid XHTML     Valid CSS2    

Langages de scripts, automatisation de commandes et

production de documents structurés :

5. La «nouvelle garde» : Python et Ruby

                     gilles.hunault "at" univ-angers.fr

 

Table des matières cliquable

  1. Python : commandes en session interactive

  2. Python : archivage incrémental de fichiers XML

  3. Python : créer les fichiers dictionnaires d'un texte

  4. Python : à réindenter

  5. Python/Tk : conversion pouce/cm

  6. Ruby : commandes en session interactive

  7. Ruby : archivage incrémental de fichiers XML

  8. Ruby : créer les fichiers dictionnaires d'un texte

  9. Ruby/Tk : conversion pouce/cm

 

Il est possible d'afficher toutes les solutions via ?solutions=1.

 

1. Python : commandes en session interactive

Essayer en mode interactif avec python 3 de donner la ou les instructions qui répondent aux mêmes questions que pour Perl en mode interactif, exercice 4 de la série 3.

Solution :  

Voici la solution avec Python 3 :


     $gh> python3
     Python 3.3.0 (default, Nov 13 2012, 10:37:00)
     [GCC 4.4.3] on linux
     Type "help", "copyright", "credits" or "license" for more information.
     
     >>> 16**4
     65536
     
     >>> 2012%128 # pas 2012^128 qui renvoie 1884
     92
     
     >>> hex(ord("A")) , int("FFF",16) , ord("a") , chr(98)
     ('0x41', 4095, 97, 'b')
     
     >>> cmd = "prog --fmt tex --nbdec 4 --fichier demo.rex"
     >>> import re
     >>> opt = re.search("--fmt (.*?) ",cmd) ; opt.group(1)
     'tex'
     
     >>> phr = "A2837 12 18 37 25"
     >>> tm = phr.split(" ")
     >>> tm.pop(0)
     'A2837'
     >>> " ".join(tm)
     '12 18 37 25'
     
     >>> f = 1
     >>> for x in range(2,9) :
     ...    f *= x
     ... # fin pour x
     ...
     >>> f
     40320
     
     >>> import datetime ; datetime.datetime.now()
     datetime.datetime(2012, 12, 1, 17, 58, 50, 252771)
     
     >>> v = "12 5 20 8 15"
     >>> s = 0
     >>> tv = v.split(" ")
     >>> for lv in tv :
     ...    s += int(lv)
     ... # fin pour lv
     ...
     >>> s /= len(tv)
     >>> s
     12.0
     
     >>> quit()
     
     

 

2. Python : archivage incrémental de fichiers XML

Implémenter une version Python de la sauvegarde incrémentale de fichiers XML comme pour l'exercice 7 de la série 2.

Solution :  

Consulter le fichier archcd.py :


     # -*- coding: iso-8859-15 -*-
     
     import os # pour os.path et os.system
     
     numarchive = 1
     nomarchive = "lesxml" + ("%03d" % numarchive) + ".tar"
     
     while (os.path.isfile(nomarchive)) :
        numarchive += 1
        nomarchive = "lesxml" + ("%03d" % numarchive) + ".tar"
     # fin de tant que
     
     specfic = "*.xml"
     cmd     = "tar -cf " + nomarchive + " " + specfic
     os.system(cmd)
     print("[python] archivage des fichiers "+ specfic + "dans " + nomarchive + " terminée")
     

 

3. Python : créer les fichiers dictionnaires d'un texte

Essayer de réaliser l'exercice 3 de la série 2 (création des dictionnaires) en Python.

Solution :  

Consulter le fichier dico.py :


     # -*- coding: iso-8859-15 -*-
     
     import sys, os, codecs, re, string
     from textwrap import dedent
     
     # aide eventuelle
     
     if (len(sys.argv)==1) :
        aide = '''
     
        dico.py ; creation des dictionnaires alphabetiques et frequentiels d'un texte
     
        syntaxe : python3 dico.py FICHIER
        exemple : python3 dico.py texte.txt
     
        les fichiers produits sont dico.tpm et dico.tpo
        dico.tpm : tri par mot croissant
        dico.tpo : tri par frequence decroissante
                   puis par mot croissant an cas d'egalite
        '''
        #print(aide.decode('iso-8859-1'))
        print(aide)
        sys.exit()
     # fin de si
     
     # si le fichier n'existe pas, on ne peut pas continuer
     
     fic = sys.argv[1]
     if (not os.path.isfile(fic)) :
        print("le fichier "+fic+" n'existe pas.\n")
        sys.exit()
     # fin de si
     
     # arrivé ici, le fichier existe
     
     exclude = set(string.punctuation)
     nbl = 0
     nbm = 0
     nbd = 0
     tdm = {}
     fh = open(fic,'r')
     for lig in fh :
        nbl += 1
        # on enlève la ponctuation
        # la ligne qui suit ne gere pas bien l'apostrophe
        # lig = ''.join(ch for ch in lig if ch not in exclude)
        lig = re.sub("[-.!;\']"," ",lig)
        lig = lig.strip()
        # on fait un tableau de mots
        tm  = lig.split(" ")
        for mot in tm :
           if (not mot=="") :
              nbm = nbm + 1
              if (not (mot in tdm)) :
                 tdm[mot]  = 1
                 nbd      += 1
              else :
                 tdm[mot] += 1
              # fin si
           # fin si
        # fin pour mot
     # fin de pour lig
     fh.close()
     
     print(" Analyse du fichier "+fic)
     print("  ",nbl," ligne(s) ",nbm," mot(s)"," et ",nbd," mots differents")
     
     # stockage alphabetique ; on en profite pour creer une structure
     # adaptee au tri frequentiel sachant que le tri en python est "stable"
     
     fn1 ="dico.tpm"
     fs1 = open(fn1,'w')
     lmo = []
     for (k,v) in sorted(tdm.items()) :
       fs1.write("%-25s %6d\n" % (k,v) )
       lmo.append((k,v))
     # fin de pour k,v
     fs1.close()
     print("le fichier ",fn1," contient les mots par ordre alphabetique.") ;
     
     # stockage frequentiel
     
     fn2 ="dico.tpo"
     fs2 = open(fn2,'w')
     #for elt in lmo.sort() :
         #fs1.write("%-25s %6d\n" % (k,v) )
         #print("%-25s %6d\n" % (k,v) )
     # fin de pour k,v
     fs2.close()
     print("le fichier ",fn2," contient les mots par ordre decroissant d'occurrences.")
     
     
     
     

 

4. Python : à réindenter

Python est un des rares langages à imposer une indentation pour les blocs. Ainsi le programme malindent.py ci-dessous n'est pas exécutable. Réindenter pour qu'il s'exécute correctement. On devra obtenir comme résultat d'exécution du fichier correct le fichier bienindent_res.txt.


     # mini mvc en python3
     
     class Model:
     def get_post(self):
     return {"title":"A test","body":"An example.."}
     
     class View:
     def display(self,items):
     print('Title:' + items['title'] + '\n'+'Body:' + items['body'])
     
     class Controller:
     def __init__(self):
     self.model=Model()
     self.view=View()
     
     def main(self):
     post=self.model.get_post()
     self.view.display(post)
     
     mvc=Controller()
     mvc.main()
     

Solution :  

Consulter le fichier bienindent.py :


     class Model :
       def get_post(self) :
         return {"title":"A test","body":"An example.."}
     
     class View :
       def display(self,items) :
         print('Title:' + items['title'] + '\n'+'Body:' + items['body'])
     
     class Controller :
       def __init__(self) :
         self.model=Model()
         self.view=View()
     
       def main(self) :
         post=self.model.get_post()
         self.view.display(post)
     
     mvc=Controller()
     mvc.main()
     

 

5. Python/Tk : conversion pouce/cm

Implémenter une version Python puis une version Python/Tk de la conversion pouce/cm définie dans l'exercice 9 de la série 3.

Solution :  

La solution est dans la page applications transversales de ce cours. On laisse le soin à la lectrice et au lecteur de retrouver cette page.

 

6. Ruby : commandes en session interactive

Essayer en mode interactif avec irb de donner la ou les instructions qui répondent aux mêmes questions que pour Perl en mode interactif, exercice 4 de la série 3.

Solution :  

 


     $gh>irb
     
     irb(main):001:0> 16**4
     => 65536
     
     irb(main):002:0> 2012%128
     => 92
     
     irb(main):003:0> [ "A"[0].to_s(16) , "FFF".to_i(16) , "a"[0].to_s(10) , "%c" % 98 ]
     => ["41", 4095, "97", "b"]
     
     irb(main):004:0> cmd = "prog --fmt tex --nbdec 4 --fichier demo.rex"
     => "prog --fmt tex --nbdec 4 --fichier demo.rex"
     
     irb(main):005:0> cmd =~ /--fmt (.*?) / ; $1
     => "tex"
     
     irb(main):006:0> phr = "A2837 12 18 37 25"
     => "A2837 12 18 37 25"
     
     irb(main):007:0> tab = phr.split(" ")
     => ["A2837", "12", "18", "37", "25"]
     
     irb(main):08:0> tab.delete_at(0)
     => "A2837"
     irb(main):09:0> tab.join(" ")
     => "12 18 37 25"
     
     irb(main):010:0>  f = 1
     => 1
     
     irb(main):011:0> (2..8).each do |n| ; f *= n ; end ; f
     => 40320
     
     irb(main):012:0> tv = "12 5 20 8 15".split(" ")
     => ["12", "5", "20", "8", "15"]
     
     irb(main):013:0> tv.each { |v| s += v.to_i }  ; s
     => 60
     
     irb(main):014:0> s /= tv.length
     => 12
     
     irb(main):015:0> Time.now
     => Sat Dec 01 19:01:18 +0100 2012
     
     irb(main):016:0> quit()
     
     

 

7. Ruby : archivage incrémental de fichiers XML

Implémenter une version Ruby de la sauvegarde incrémentale de fichiers XML comme pour l'exercice 7 de la série 2.

On profitera pour vérifier que l'exécution du script archcdtout.sh pour bash fournit bien le résultat escompté indiqué dans la solution.

Solution :  

Consulter le fichier archcd.rb :


     numarchive = 1
     nomarchive = "lesxml" + sprintf("%03d",numarchive) + ".tar"
     
     while File.exists?(nomarchive)
         numarchive += 1
         nomarchive  = "lesxml" + sprintf("%03d",numarchive) + ".tar"
     end # fin tant que
     
     specfic = "*.xml"
     cmd     = "tar -cf " + nomarchive + " " + specfic
     rc      = IO.popen(cmd)
     print "[ruby] archivage des fichiers "+ specfic + "dans " + nomarchive + " OK.\n"
     

Le script bash proposé archcdtout.sh efface toutes les archives lesxml*.tar puis exécute chacun des script d'archivage incrémental dans les différents langages.


     # fichier archcdtout
     
     rm     lesxml*.tar
     regina archcd.rex
     perl   archcd.pl
     wish   archcd.tcl
     php    archcd.php
     python archcd.py
     ruby   archcd.rb
     

Si tout se passe bien, on doit obtenir (au cadrage et aux encodages près) :


     [rex]      archivage des fichiers *.xml dans lesxml001.tar OK
     [perl]     archivage des fichiers *.xml dans lesxml002.tar terminée
     [tcl]      archivage des fichiers *.xml dans lesxml003.tar terminée.
     [php]      archivage des fichiers *.xml dans lesxml004.tar terminée
     [python]   archivage des fichiers *.xml dans lesxml005.tar terminée
     [ruby]     archivage des fichiers *.xml dans lesxml006.tar terminée.
     

 

8. Ruby : créer les fichiers dictionnaires d'un texte

Essayer de réaliser l'exercice 3 de la série 2 (création des dictionnaires) en Ruby.

Solution :  

Consulter le fichier dico.rb :


     # encoding: ISO-8859-15
     
     # # (gH)   -_-  dico.rb  ;  TimeStamp (unix) : 20 Février 2015 vers 18:09
     
     # aide éventuelle
     
     if ARGV.empty? then
        puts " syntaxe : ruby dico.rb FICHIER"
        puts " exemple : ruby dico.rb candide.txt"
        exit(-1)
     end # fin si
     
     # test si le fichier est présent
     
     nomfictxt = ARGV.first
     puts " lecture de #{nomfictxt} "
     
     if !File.exists?(nomfictxt) then
        puts " fichier #{nomfictxt} non vu. Stop."
        exit(-1)
     end # fin si
     
     # arrivé ici, on peut construire le dictionnaire
     
     nbl    = 0 # nombre de lignes
     nbm    = 0 # nombre de mots
     freqs  = Hash.new(0)
     fictxt = File.open(nomfictxt, "r:ISO-8859-15")
     fictxt.each_line { |ligne|
       nbl = nbl + 1
       # suppression de la ponctuation
       ligne.tr!("!?,;.'","       ")
       ligne.gsub!(/--/,"")
       # on découpe en mots
       ligne.downcase.split(/\s+/).each { |mot|
         freqs[mot] += 1
         nbm += 1
       } # fin pour chaque mot
     } # fin pour chaque ligne
     
     puts "#{nbm} mots vus sur #{nbl} lignes."
     
     # tri alphabétique et affichage
     
     puts "Dictionnaire alphabétique"
     puts "-------------------------"
     
     freqs.sort.each { |mot,cnt|
       puts sprintf("%-15s  %5d",mot,cnt)
     } # fin pour chaque mot
     
     # tri par fréquence et affichage
     
     puts "Dictionnaire fréquentiel"
     puts "------------------------"
     
     freqs.sort_by{ |k, v| [-v,k] }.each { |mot,cnt|
       puts sprintf("%-15s  %5d",mot,cnt)
     } # fin pour chaque mot
     

 

9. Ruby/Tk : conversion pouce/cm

Implémenter une version Ruby puis une version Ruby/Tk de la conversion pouce/cm définie dans l'exercice 9 de la série 3.

Solution :  

La solution est dans la page applications transversales de ce cours. On laisse le soin à la lectrice et au lecteur de retrouver cette page.

 

 

Code-source php de cette page ; code javascript utilisé. Retour à la page principale du cours.

 

 

retour gH    Retour à la page principale de   (gH)