Solutions des exercices du tuteur Perl (gH)
Téléchargez l'archive des programmes perl présentés.
Solution de l'exercice "E1. numérotation des lignes d'un fichier"
Si l'énoncé n'avait pas demandé que les numéros de ligne soient biens cadrés, on aurait pu, sous Unix, se contenter d'utiliser la commande grep -n "" nom_fichier.
Une solution classique vérifie l'existence du paramètre, l'ouverture possible du fichier avant de nommer $lig la ligne vue dans le fichier avec une variable explicite nommée $numero qu'on incrémente dans la boucle de lecture, soit le programme :
# test des paramètres if ($ARGV[0] eq "") { print " syntaxe : perl numerote.pl nom_de_fichier \n" ; exit(-1) ; } ; # fin de test sur les arguments $fichier = $ARGV[0] ; # récupération du nom du fichier # ouverture du fichier open( FIC ,"<$fichier") || die "\n impossible d'ouvrir le fichier nommé $fichier \n\n" ; # affichage numéroté $numero = 0 ; while ($lig=<FIC>) { $numero++ ; print sprintf(" %04d ",$numero).$lig ; } ; # fin de tant queUne écriture plus "perlienne" vient utiliser les variables spéciales aux noms barbares à savoir $. et $_ :
die(" syntaxe : perl numerote.pl nom_de_fichier \n ") if ($ARGV[0] eq "") ; open( FIC ,"<$ARGV[0]") or die "\n impossible d'ouvrir le fichier nommé $ARGV[0] \n\n" ; while (<FIC>) { print sprintf(" %04d ",$.).$_ ; } ;Solution de l'exercice "E2. variables d'environnement"
Une solution classique consiste à stocker dans un fichier-texte le résultat de la commande set puis à parcourir les lignes et à les découper (le séparateur est le symbole "égale"), soit le programme :
print "\n Variable Valeur\n\n" ; $ficenv = "set.tmp" ; # sauvegarde dans un fichier `set > $ficenv ` ; # parcours du fichier open(FENV,"<$ficenv") or die ("impossible d'ouvrir $ficenv") ; $nbve = 0 ; while ($ligne=<FENV>) { $nbve++ ; chop($ligne) ; @ligenv = split(/=/,$ligne) ; ($tvar[$nbve],$tval[$nbve]) = @ligenv ; } ; # fin de tant que # affichage for ($idve=1;$idve<=$nbve;$idve++) { print sprintf(" %-20s",$tvar[$idve]) .sprintf("%-40s",$tval[$idve])."\n" ; } ; # fin de pour chaqueRemarque : au lieu de@ligenv = split(/=/,$ligne) ; ($tvar[$nbve],$tval[$nbve]) = @ligenv ;on aurait pu écrire :($tvar[$nbve],$tval[$nbve]) = split(/=/,$ligne) ;Une solution plus "perliste" consiste à savoir que la table de hachage nommée %ENV contient les variables d'environnement et leurs valeurs. On remarquera qu'on trie au passage (ce qui n'est sans doute pas nécessaire) les clés sans utiliser keys car Perl s'en doute !
print "\n Variable Valeur\n\n" ; foreach $ve (sort %ENV) { if (defined $ENV{$ve}) { print sprintf(" %-20s",$ve) .sprintf("%-40s",$ENV{$ve})."\n" ; } ; # fin de si variable définie } ; # fin de pour chaque
Pour l'affichage en cgi avec de la couleur, nous renvoyons le lecteur au code-source de la page http://forge.info.univ-angers.fr/scripts/env.pl
Solution de l'exercice "E3. dictionnaires d'un fichier-texte"
Nous laissons (comme nouvel exercice) le soin au lecteur de détailler les instructions Perl utilisées. A part =~, tr et s/ toutes ces instructions ont déja été vues...
# test des paramètres if ($ARGV[0] eq "") { print " syntaxe : perl dicos.pl nom_de_fichier \n" ; exit(-1) ; } ; # fin de test sur les arguments $fictxt = $ARGV[0] ; # récupération du nom du fichier # ouverture du fichier open( FICT ,"<$fictxt") || die "\n impossible d'ouvrir le fichier nommé $fictxt \n\n" ; # parcours du fichier, remplissage du hachage au passage $nbLig = 0 ; # nombre de lignes du fichier $nbMot = 0 ; # nombre de mots en tout $nbMdi = 0 ; # nombre de mots différents while ($ligne=<FICT>) { $nbLig++ ; chop($ligne) ; # on élimine la ponctuation $ligne =~ tr/,.:!'"();/ / ; # on élimine le double tiret $ligne =~ s/--//g ; @mots = split(/ /,$ligne) ; foreach $m (@mots) { if (length($m)>0) { $nbMot++; $cntMot{$m}++ ; if ($cntMot{$m}==1) { $nbMdi++ ; } ; # finsi nouveau mot } ; # finsi mot non vide } ; # fin pour chaque mot } ; # fin de tant que print " Analyse du fichier $fictxt :\n" ; print " $nbLig ligne(s), $nbMot mot(s) dont $nbMdi mot(s) différent(s).\n" ; $dicNom = "dic_$fictxt.mot" ; # fichier alphabétique $dicOcc = "dic_$fictxt.occ" ; # fichier fréquenciel open(DICM,">$dicNom ") or die ("impossible d'écrire dans $dicNom") ; print DICM "fichier $dicNom issu de $0 $fictxt\n" ; foreach $m (sort keys(%cntMot)) { print DICM sprintf(" %-20s",$m) .sprintf("%4d",$cntMot{$m})."\n" ; # on en profite pour remplir un tableau pour les occurences $cle = sprintf("%04d",$cntMot{$m})."_$m" ; $tabMot{$cle}=$m ; } ; # fin pour chaque close(DICM) ; open(DICK,">$dicOcc ") or die ("impossible d'écrire dans $dicOcc") ; print DICK "fichier $dicOcc issu de $0 $fictxt\n" ; foreach $c (reverse sort keys(%tabMot)) { # on sait comment Perl convertit les %s en %c, on en profite : print DICK sprintf(" %-20s",$tabMot{$c}) .sprintf("%4d",$c)."\n" ; } ; # fin pour chaque close(DICK) ; print " Vous pouvez consulter les fichiers $dicNom et $dicOcc \n" ; print " dont voici le début : \n\n" ; system("head -n 20 $dicNom") ; system("head $dicOcc") ;
Solution de l'exercice "E4. calcul de Chi2"
Installer un module consiste à recopier le fichier-texte correspondant dans "le bon répertoire". Lorsqu'on est root, ceci peut se faire en ligne de commande. Si on dispose des droits suffisants, pour notre exemple, on écrit seulement
perl -MCPAN -e 'install Statistics::Distributions'L'utilisateur courant peut alors se contenter d'écrireuse Statistics::Distributions ; $df = 17 ; $pr = 5 ; $vc = Statistics::Distributions::chisqrdistr ($df,$pr); print " valeur de chi2 : $vc \n" ;Si par contre on de dispose pas des droits root, il est possible de copier le fichier localement et de l'indiquer à perl. Par exemple si on crée le répertoire /home/info/gh/Bin/Perl_lib/, si on y crée ensuite le répertoire /home/info/gh/Bin//Perl_lib/Statistics et si on met le fichier Distributions.pm dans ce répertoire Statistics alors il suffit d'ajouter au début du programme perl précédent la ligneuse lib "/home/info/gh/Bin/Perl_lib" ;pour que perl aille chercher ce qu'il lui manque comme module à l'endroit indiqué.Solution de l'exercice "E5. fichiers DBF"
Le format Dbase et plus généralement le format Xbase sont des formats qui permettent de stocker "proprement" des tableaux rectangulaires de données. Sans être des fichiers de base de données lourdes comme Oracle ou Sql, ces fichiers sont lisibles par la plupart des logiciels comme Excel ou les autres tableurs courant. Leur grand intérêt est d'utiliser comme unité de base de structure les colonnes (ou "champs"). Ils garantissent donc la constance du nombre de champs sur l'ensemble des lignes et l'homogénéité des données à l'intérieur d'une même colonne. De plus ils sont très économiques en terme de stockage car après la définition des colonnes on trouve les données bout à bout sans caractère de controle. Ainsi pour 18 lignes de 59 caractères soit 1062 octets, le fichier DBF fait 1384 octets (soit moins de 2 kO) alors que le même fichier lu sous Excel 10 et enregistré au format XLS fait 14 384 octets soit plus de 14 kO c'est à dire 10 fois plus !. Après avoir lu la page de man de XBASE disponible ici il est relativement simple d'écrire le programme dbase.pl suivant :
use lib "/home/gh/Bin"; use XBase ; $nomBase = "vins.dbf" ; $table = new XBase $nomBase or die XBase-\>errstr; $nbr = $table-\>last_record ; print " il y a ".(1+$nbr)." enregistrements dans la base $nomBase ; for (0 .. $nbr) { print sprintf("%5d. ",1+$_) ; @enrc = $table->get_record($_) ; $ndc = -1 ; foreach $ch (@enrc) { $ndc++ ; if ($ndc>0) { print "$ch" ; } } ; # fin pour chaque champ print "\n \n" ; } ; # fin pour enregistrementSi on l'applique au fichier vins.dbf proposé, on voit alors :il y a 18 enregistrements dans la base vins.dbf 1. CHMP 7069 3786 12578 8037 13556 9664 10386 206 2. MOS1 2436 586 2006 30 1217 471 997 51 3. MOS2 3066 290 10439 1413 7214 112 3788 330 4. ALSA 2422 1999 17183 57 1127 600 408 241 5. GIRO 22986 22183 21023 56 30025 6544 13114 3447 6. BOJO 17465 19840 72977 2364 39919 17327 17487 2346 7. BORG 3784 2339 4828 98 7885 3191 11791 1188 8. RHON 7950 10537 7552 24 8172 11691 1369 1798 9. ANJO 2587 600 2101 0 7582 143 872 131 10. AOCX 17200 22806 15979 50 20004 1279 4016 944 11. VDQS 1976 1029 1346 0 2258 212 1017 487 12. XXXX 38747 19151 191140 7992 101108 1029 26192 38503 13. PROV 1375 1150 2514 0 284 401 9 236 14. MUSC 2016 2908 1529 0 12891 18 716 653 15. RHOF 785 1648 1009 6 775 643 542 35 16. AOCF 160 246 135 8 1177 26 7 0 17. XXXF 24 1533 160 0 480 0 0 0 18. XXFF 2415 74 208 8 1705 12 36 47En, rajoutant les instructions de tableau TR, TD etc. (voir le programme dbaset.pl) on obtient alors le joli affichage de la page dbaset.htmSolution de l'exercice "E6. extractions d'adresses"
Lorsqu'on met .* perl cherche à satisfaire l'expression régulière en mode gourmand sans garder une trace de ce qui correspond. Mettre ? permet de satisfaire l'expression régulière en mode modéré et utiliser les parenthèses met en mémoire ce qui correspond dans les variables $1, $2 etc.
Ici, on veut dans une ligne comme <a href="www.google.fr">google</a> récupérer les champs entre <a href=" et le guillemet suivant et récupérer aussi ce qu'il y a entre le > et </a> ; comme on veut pas récupérer ce qu'il y a entre les deux (comme par exemple target="_blank" ) on ne met pas de parenthèses.
Si on met +=1 l'affectation est faite après l'affichage après et on ne voit que les références utilisées au moins 2 fois, soit :
Homo sapiens http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Homo+sapiens Mus musculus http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Mus+musculus Sus scrofa http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Sus+scrofa Pseudomonas aeruginosa http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Pseudomonas+aeruginosa Escherichia coli http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Escherichia+coli Bos taurus http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Bos+taurus Bacillus stearothermophilus http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Bacillus+stearothermophilus Spinacia oleracea http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?name=Spinacia+oleracea
Solution de l'exercice "E7. que fait ce programme ?"
Visiblement, ce programme perl attend en entrée le nom d'un fichier php. Il lit ce fichier ainsi que tous les fichiers inclus (via include, include_onc et require_once). Quand un fichier à inclure n'est pas vu, le programme le dit et s'arrête. Si tous les fichiers sont vus, ldpphp.pl passe en revue toutes les définitions de fonctions et indique leur nom et position dans le fichier. Ensuite, ldphp.pl fournit la liste des fonctions par fichier. Le fichier produit est nommé ldphp.sor. Voici son contenu pour std.php (qui inclut strfun.php) :
Analyse du fichier std.php ========================== 28/01/2011 9:51 Liste des fichiers inclus ------------------------- (format : nom du fichier et nombre de lignes dans le fichier) 1. * std.php 1337 2. strfun.php 250 total 1587 lignes Liste des fonctions (et position dans le fichier) -------------------- 1. abbr std.php 1001 2. afficheRubrique 0 3. ahref std.php 1070 4. aname std.php 1082 5. ancre std.php 1054 6. b std.php 391 7. blockquote std.php 705 8. br std.php 661 9. center std.php 697 10. cmt std.php 465 11. code std.php 649 12. comptageSqlSimple std.php 1190 13. compteMots strfun.php 31 14. copies strfun.php 15 15. dd std.php 507 16. debutPage std.php 71 17. debutPageGeneral std.php 155 18. debutPageMinimal std.php 1148 19. debutPageMinimale std.php 300 20. debutPageRedir std.php 331 21. debutSection std.php 364 22. debutdd std.php 511 23. debutdl std.php 527 24. debutdt std.php 519 25. debutli std.php 495 26. div std.php 783 27. dt std.php 503 28. em std.php 397 29. fieldset std.php 813 30. finPage std.php 251 31. finPageGeneral std.php 273 32. finPageMinimal std.php 1179 33. finPageMinimale std.php 318 34. finSection std.php 376 35. finabbr std.php 1005 36. finblockquote std.php 709 37. fincenter std.php 701 38. fincode std.php 657 39. findd std.php 515 40. findiv std.php 794 41. findl std.php 531 42. findt std.php 523 43. finfieldset std.php 821 44. finform std.php 585 45. finli std.php 499 46. finnoscript std.php 997 47. finol std.php 487 48. finp std.php 689 49. finpre std.php 611 50. finselect std.php 962 51. finspan std.php 555 52. fintable std.php 719 53. fintd std.php 759 54. fintdk std.php 779 55. fintextarea std.php 989 56. finth std.php 767 57. fintr std.php 729 58. finul std.php 479 59. form std.php 809 60. gbleu std.php 563 61. gbleuf std.php 571 62. ghBleu std.php 1020 63. ghRouge std.php 1014 64. grouge std.php 559 65. gvert std.php 575 66. gvertf std.php 579 67. h std.php 409 68. h1 std.php 422 69. h2 std.php 428 70. h3 std.php 434 71. h4 std.php 438 72. hh1 std.php 445 73. hh2 std.php 455 74. hh3 std.php 461 75. hr std.php 798 76. href std.php 1076 77. img std.php 1027 78. imgh std.php 1045 79. input_checkbox std.php 857 80. input_hidden std.php 840 81. input_option std.php 966 82. input_password std.php 851 83. input_radio std.php 865 84. input_reset std.php 885 85. input_select std.php 954 86. input_select_fin std.php 958 87. input_submit std.php 876 88. input_text std.php 844 89. js std.php 1124 90. jsf std.php 1134 91. kbd std.php 403 92. label std.php 825 93. legende std.php 830 94. li std.php 491 95. listeSelectFromTxt std.php 974 96. menu 0 97. mot strfun.php 61 98. nbdif strfun.php 210 99. nbmots strfun.php 95 100. nbsp std.php 669 101. noscript std.php 993 102. ol std.php 483 103. on 0 104. on 0 105. on 0 106. on 0 107. on 0 108. on 0 109. p std.php 589 110. pct std.php 1207 111. pj std.php 685 112. pre std.php 600 113. pre_fichier std.php 615 114. premierCarNonNul strfun.php 125 115. ptexte std.php 681 116. pvide std.php 693 117. rubriqueParNumero 0 118. s_gbleu std.php 567 119. s_nbsp std.php 677 120. s_span std.php 540 121. sbr std.php 665 122. sdl std.php 469 123. setNumcrub 0 124. showurl std.php 1110 125. showurlbr std.php 1118 126. showurlcmt std.php 1098 127. showurlcmtbr std.php 1088 128. snbsp std.php 673 129. span std.php 551 130. surncard strfun.php 165 131. surncardnbsp strfun.php 195 132. surncardzero strfun.php 180 133. surncarg strfun.php 150 134. table std.php 713 135. tableauDar std.php 1279 136. td std.php 733 137. tdk std.php 771 138. tdm 0 139. tdvide std.php 763 140. textarea std.php 894 141. textarea_fichier std.php 911 142. th std.php 746 143. titre 0 144. tr std.php 723 145. ul std.php 475 Fonction(s) du fichier std.php (et position dans le fichier) ------------------------------ 1. abbr 1001 2. ahref 1070 3. aname 1082 4. ancre 1054 5. b 391 6. blockquote 705 7. br 661 8. center 697 9. cmt 465 10. code 649 11. comptageSqlSimple 1190 12. dd 507 13. debutPage 71 14. debutPageGeneral 155 15. debutPageMinimal 1148 16. debutPageMinimale 300 17. debutPageRedir 331 18. debutSection 364 19. debutdd 511 20. debutdl 527 21. debutdt 519 22. debutli 495 23. div 783 24. dt 503 25. em 397 26. fieldset 813 27. finPage 251 28. finPageGeneral 273 29. finPageMinimal 1179 30. finPageMinimale 318 31. finSection 376 32. finabbr 1005 33. finblockquote 709 34. fincenter 701 35. fincode 657 36. findd 515 37. findiv 794 38. findl 531 39. findt 523 40. finfieldset 821 41. finform 585 42. finli 499 43. finnoscript 997 44. finol 487 45. finp 689 46. finpre 611 47. finselect 962 48. finspan 555 49. fintable 719 50. fintd 759 51. fintdk 779 52. fintextarea 989 53. finth 767 54. fintr 729 55. finul 479 56. form 809 57. gbleu 563 58. gbleuf 571 59. ghBleu 1020 60. ghRouge 1014 61. grouge 559 62. gvert 575 63. gvertf 579 64. h 409 65. h1 422 66. h2 428 67. h3 434 68. h4 438 69. hh1 445 70. hh2 455 71. hh3 461 72. hr 798 73. href 1076 74. img 1027 75. imgh 1045 76. input_checkbox 857 77. input_hidden 840 78. input_option 966 79. input_password 851 80. input_radio 865 81. input_reset 885 82. input_select 954 83. input_select_fin 958 84. input_submit 876 85. input_text 844 86. js 1124 87. jsf 1134 88. kbd 403 89. label 825 90. legende 830 91. li 491 92. listeSelectFromTxt 974 93. nbsp 669 94. noscript 993 95. ol 483 96. p 589 97. pct 1207 98. pj 685 99. pre 600 100. pre_fichier 615 101. ptexte 681 102. pvide 693 103. s_gbleu 567 104. s_nbsp 677 105. s_span 540 106. sbr 665 107. sdl 469 108. showurl 1110 109. showurlbr 1118 110. showurlcmt 1098 111. showurlcmtbr 1088 112. snbsp 673 113. span 551 114. table 713 115. tableauDar 1279 116. td 733 117. tdk 771 118. tdvide 763 119. textarea 894 120. textarea_fichier 911 121. th 746 122. tr 723 123. ul 475 Fonction(s) du fichier strfun.php (et position dans le fichier) --------------------------------- 1. compteMots 31 2. copies 15 3. mot 61 4. nbdif 210 5. nbmots 95 6. premierCarNonNul 125 7. surncard 165 8. surncardnbsp 195 9. surncardzero 180 10. surncarg 150
Pour quelqu'un qui développe en PHP, cela peut-être utile, en complément à stdphp.php.
Retour au tuteur Perl (gH)
Retour à la page principale de (gH)