IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

GENÈSE D'UN DICTIONNAIRE

Construction d'un lexique interactif avec Lazarus


précédentsommairesuivant

Affichage sous Lazarus

Introduction

Le premier chapitre a conduit au chargement d'un fichier texte. Fichier quand même exceptionnel puisqu'il apporte plus de 336 000 mots de la langue française !
Cette liste est consultable à l'aide d'un programme courant, style bloc-notes ou WordPad, mais l'intérêt de cette consultation reste alors très restreint. Un outil tel que Lazarus va ouvrir des possibilités intéressantes. Dans ce chapitre seront présentées trois méthodes de lecture, et une technique d'évaluation.
Dans le chapitre suivant, le programme sera complété pour aborder différentes façons d'afficher et de balayer le texte.

Démarrage de Lazarus

Votre ordinateur dispose de Lazarus d'un côté, du fichier de mots d'un autre. Pour simplifier les explications à venir, nous vous proposons de créer un répertoire Lexique dans lequel seront ouverts les sous-répertoires Docs et Lex1.

Le répertoire Docs recevra les documents textes et pour commencer, le fichier de mots.

Lex1 sera réservé à Lazarus, donc au programme source, au programme compilé et à l'ensemble des fichiers de service.

Pour les chapitres suivants, on créera le répertoire Lex2, Lex3, etc. de façon à faciliter à chaque instant le retour à un état antérieur du programme.

Lancez Lazarus, cliquez sur Fichier/Nouveau/Application. Au premier plan apparaît une fenêtre intitulée Form1 : c'est elle qui recevra les boutons de commande et les modules d'affichage.

Au second plan s'ouvre la fenêtre de l'éditeur de code intitulée Éditeur de source.

Sauvegarde de l'unité

La première ligne de l'éditeur s'intitule unit Unit1 ; cliquez sur Fichier/Enregistrer sous. Choisissez :

  • votre répertoire de travail, par exemple Lex1 ;
  • le nom de votre unité, par exemple uLex1, sauvegardez, option Préserver le nom.

Le fichier uLex1.pas est créé dans le répertoire Lex1.

Image non disponible

Sauvegarde du projet

Dans le menu, sous le mot Fichier, se présente une icône avec le menu contextuel Nouvelle unité. Sous cette icône, une autre avec l'information Afficher les Unités. Cliquez sur cette seconde icône : deux unités sont listées. La première, uLex1, est celle que l'on vient de créer. Cliquez sur la seconde et enregistrez sous le nom de pLex1.

L'unité et le projet sont en sécurité sur votre disque dur. Toutes les modifications seront enregistrées et Lazarus permettra un retour en arrière après toute une série de saisies.

Cette phase préalable d'enregistrement (choix du répertoire, enregistrement de l'unité et du projet) est fondamentale sous Lazarus, qui connaît dorénavant son espace de travail : votre programme est maintenant localisé et la compilation (construction du fichier exe) se fera dans le répertoire que vous aurez choisi.

Interface graphique

Pour l'instant, l'interface graphique se présente sous la forme d'une fenêtre intitulée Form1. Nous nous limiterons, dans l'immédiat, à trois modifications :

  • Nom de l'interface. Dans le menu Fenêtre de Lazarus, sélectionnez Form1. Cliquez dans cette fenêtre pour indiquer à Lazarus que vous vous intéressez à cet objet précis. Effectivement, Lazarus, dans sa fenêtre Inspecteur d'objets a sélectionné la ligne Form1:TForm1 . Au-dessous, dans l'onglet Propriétés, ligne Caption, on lit Form1. Remplacez ce nom par Lex1 : immédiatement le nouveau nom s'affiche en tête de notre interface graphique ;
  • Bouton.

    Image non disponible

    Sous la ligne du menu, cliquez sur le bouton marqué Ok, puis cliquez au centre de la fenêtre Lex1 : un bouton appelé Button1 apparaît. Dans l'inspecteur d'objets, la sélection a basculé sur ce nouvel objet. Dans l'onglet Propriétés, ligne Caption, remplacez Button1 par Lire ;
  • Texte. Sous la ligne du menu, à côté du bouton, figure un objet qui se présente sous le sigle Abc. Cliquez dessus, puis cliquez dans l'interface graphique : l'objet Label1 apparaît. Il est sélectionné automatiquement dans l'inspecteur d'objets.

L'interface est minimaliste, mais nous aurons l'occasion de l'enrichir !

Code

Nous voilà maintenant au pied du mur : nous imaginons un clic sur le bouton, qui déclenche la lecture du fichier texte, et une information apparaît sur l'interface pour signaler que l'opération s'est déroulée normalement.

Voici le code qui permet la lecture du fichier texte :

 
Sélectionnez
procedure LireListeDeMots;
var
  MotCour: string;
  lettre: char;
  fLex:   file;
  listeMots : TStringList;
begin
  TopChro := 0;
  TopChrono('');
  listeMots := TStringList.Create;
  AssignFile(fLex, 'liste.de.mots.francais.frgut.txt');
   {$I-}
  Reset(fLex, 1);
   {$I+}
  if IOResult = 0 then
  begin
    Seek(fLex, 0);
    MotCour := '';
    while not EOF(fLex) do
    begin
      BlockRead(fLex, lettre, 1);
      if lettre <> Chr(10) then
        MotCour := MotCour + lettre
      else
      begin
        listeMots.Append(MotCour);
        MotCour     := '';
      end;
    end;
    CloseFile(fLex);
    TopChrono('Lecture octets');
    Form1.Label1.Caption := 'Dernier mot (n° '
        + IntToStr(listeMots.Count) + ') : ' + listeMots.Strings[listeMots.Count-1];
  end
  else
    ShowMessage('Erreur d''accès au fichier');
  Beep;
end;

Il faut copier ce texte dans l'éditeur de source, sous la ligne implementation. Le compilateur cherchera le fichier texte dans le répertoire de travail : il faut donc copier le fichier de mots (en principe dans le répertoire Docs) dans le répertoire de travail, Lex1.

Un clic sur le petit triangle vert (sous le mot Éditer dans le menu Lazarus) déclenche un contrôle général du projet, sa compilation et son exécution (en mode débogage).

Si rien ne se passe, c'est que tout va bien, le compilateur a fait son travail jusqu'au bout sans rencontrer de problème. Si une erreur est intervenue, lisez attentivement les informations présentées dans la fenêtre Messages. Corrigez selon les indications données.

Pour revenir en mode édition, il suffit de cliquer sur le carré rouge, à droite du triangle vert : le mode débogage est arrêté, l'édition du programme peut reprendre.

À quoi sert le bouton Lire ? Pour l'instant, le programme n'inclut aucune instruction pour le cas où l'on cliquerait dessus ! Cette omission va être rapidement corrigée.

Dans l'interface graphique Lex1, cliquez une fois sur le bouton Lire : son cadre est souligné par huit petits carrés permettant par exemple de modifier sa forme. Dans la fenêtre Inspecteur d'objets, l'objet Button1 est alors sélectionné. Dans la partie inférieure de la fenêtre, dans l'onglet Propriétés, cliquez sur la ligne OnClick : à droite, trois points apparaissent ; cliquez dessus : l'éditeur de source est immédiatement enrichi d'une nouvelle procédure, et le curseur d'édition clignote entre les instructions begin et end ;

Une seule instruction est à écrire :

LireListeDeMots

qu'il faut terminer par un point-virgule « ; ».

Dans la pratique, notre programme uLex1 fabrique (à l'aide de tout l'environnement Lazarus évidemment) une interface graphique Lex1 avec un bouton et une ligne de texte.

Lorsque l'on clique sur le bouton, le programme exécute la procédure LireListeDeMots. Quand celle-ci est terminée, la ligne de texte nous présente les informations voulues.

Cliquez sur le petit triangle vert pour compiler. Cliquez sur le bouton Lire et… patientez, car la lecture du fichier de mots peut durer de 30 à 60 secondes selon le matériel utilisé. L'information voulue apparaît enfin :

Image non disponible

Deuxième méthode

L'accès au contenu du fichier par l'intermédiaire de Lazarus semble bien lent. En effet, le code contient l'instruction

BlockRead(fLex, lettre, 1);

qui impose au matériel de lire le fichier lettre par lettre, chaque lettre occupant un octet. Comme le fichier a une longueur de 3,7 mégaoctets, il y a autant d'accès disque, ce qui est pénalisant.

La seconde méthode consiste à regrouper la lecture par blocs de textes (les mots) séparés par un octet de retour à la ligne. Le code devient alors :

 
Sélectionnez
procedure LireListe2;
var
  MotCour: string;
  fLex:   TextFile;
  listeMots : TStringList;
begin
  listeMots := TStringList.Create;
  AssignFile(fLex, 'liste.de.mots.francais.frgut.txt');
   {$I-}
  Reset(fLex);
   {$I+}
  if IOResult = 0 then
  begin
    while not EOF(fLex) do
    begin
      ReadLn(fLex, MotCour);
      listeMots.Append(MotCour);
    end;
    CloseFile(fLex);
    Form1.Label1.Caption := 'Lecture par mot ; mot (n° '
        + IntToStr(listeMots.Count) + ') : ' + listeMots.Strings[listeMots.Count-1];
  end
  else
    ShowMessage('Erreur d''accès au fichier');
  Beep;
end;

Pour lancer cette procédure, on va ajouter un bouton, appelé Lire2, et dans la procédure OnClick de ce bouton, glisser l'instruction LireListe2 ; un clic sur le petit triangle vert pour compiler, un clic sur le bouton Lire2 et… cette fois on apprécie une réaction presque immédiate.

Le premier mode de lecture imposait un déchiffrage caractère par caractère, et le second passe directement d'un mot à l'autre. En gros, les accès disques passent de 3 700 000 (nombre d'octets) à 330 000 (nombre de mots).
Plus loin nous verrons comment évaluer précisément la performance.

Troisième méthode

Le rythme pourrait encore s'accélérer si la lecture pouvait s'opérer d'un bloc, avec une séparation automatique des mots…

Cela est possible en remplaçant les instructions BlockRead (version 1) ou ReadLn (version 2) par l'instruction de haut niveau

listeMots.LoadFromFile(nomFichier)

(listeMots est la liste utilisée précédemment). LoadFromFile indique tout simplement qu'il faut la remplir à partir du fichier précisé.

Le code se réduit encore :

 
Sélectionnez
procedure LireListeTexte;
var
  listeMots : TStringList;
begin
  listeMots := TStringList.Create;
  listeMots.LoadFromFile('liste.de.mots.francais.frgut.txt');
  Form1.Label1.Caption := 'Lecture 3 ; dernier mot (n° '
        + IntToStr(listeMots.Count) + ') : ' + listeMots.Strings[listeMots.Count-1];
  Beep;
end;

Pour lancer cette procédure, on va ajouter un bouton, appelé Lire3, et dans la procédure OnClick de ce bouton, glisser l'instruction :

LireListeTexte ;

Un clic sur le petit triangle vert pour compiler, un clic sur le bouton Lire3 et… cette fois on apprécie encore. Simplicité et efficacité.

Chronomètre

Pour y voir clair sur les performances de tel ou tel programme, rien de tel que de mesurer la durée qui sépare le démarrage d'une tâche et son achèvement.

Il existe dans la bibliothèque LCL une fonction GetTickCount qui donne, en millièmes de seconde, la position du compteur Temps du processeur. Pour rendre cette fonction accessible, il suffit de rajouter dans la ligne uses l'unité LclIntf :

 
Sélectionnez
unit uLex1; 
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, LclIntf;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

Lazarus saura identifier l'instruction GetTickCount ; le code de la procédure pourrait s'écrire ainsi :

 
Sélectionnez
procedure TopChrono(Info : string);
begin
  if TopChro = 0 then
  begin
    TopChro := GetTickCount;
    Form1.Memo1.Append('Départ chrono');
  end
  else
     Form1.Memo1.Append(Info +' Durée du processus '
                             + IntToStr(GetTickCount-TopChro)+' ms');
end;

La procédure modifie la variable globale TopChro. Si elle vaut 0, le champ Memo signale le départ du chronomètre. Sinon, le Memo présente l'écart de temps, en millisecondes, depuis le départ.

Pour que ce code soit utilisable, il convient de :

Primo, déclarer la variable globale TopChro ; pour cela, sous les lignes :

var Form : Tform1 ;

on ajoute :

TopChro : integer ;

Secundo, ajouter un composant Memo dans l'interface graphique : ce composant est présenté dans le menu Lazarus entre le bouton marqué Ok, déjà utilisé, et le bouton marqué on. On clique une fois sur le composant, une fois sur l'interface Lex1 et on agence l'ensemble pour obtenir sensiblement la présentation suivante :

Image non disponible

Le champ Memo dispose également de nombreuses propriétés directement accessibles dans l'inspecteur d'objets : cliquez sur la propriété Scrollbars ; faites passer le paramètre de ssNone à ssAutoBoth.
Ainsi, les ascenseurs latéral et vertical permettront de naviguer sans difficulté dans ce composant.

Tertio, compléter chaque procédure de lecture par une mise à zéro de la variable globale et un premier appel à TopChrono, ceci en début de procédure, et un second appel à TopChrono en fin de procédure.

Pour vérifier que tout fonctionne, compilez, et cliquez successivement sur les boutons Lire, Lire2 et Lire3.

Les mesures de durée sont affichées dans le mémo.

Sur une machine, on obtient par exemple :

Type de lecture Durée millisecondes
Octet par octet 39171
Mot par mot 437
Globale 156

Conclusion

Une bonne utilisation du code permet de réaliser des économies spectaculaires dans les temps d'accès.

En l'occurrence, l'instruction BlockRead se révèle désastreuse par rapport à l'instruction LoadFromFile.

Alors, pourquoi l'avoir utilisée ?

D'abord pour les besoins de comparaison : aucune solution ne peut être a priori considérée comme la meilleure.

Ensuite parce que, la suite le montrera, cette instruction nous sera bien utile !

Le présent chapitre a montré comment Lazarus permet de lire un fichier de mots. Le suivant abordera l'affichage des mots et le balayage du fichier depuis le début jusqu'à la fin.

L'unité uLex1 se présente dorénavant comme suit :

L'unité uLex1
TéléchargerSélectionnez
unit uLex1; 
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, LclIntf;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 
 
var
  Form1: TForm1; 
  TopChro : integer;
implementation
 
{ TForm1 }
procedure TopChrono(Info : string);
begin
  if TopChro = 0 then
  begin
    TopChro := GetTickCount;
    Form1.Memo1.Append('Départ chrono');
  end
  else
     Form1.Memo1.Append(Info +' Durée du processus '
                             + IntToStr(GetTickCount-TopChro)+' ms');
end;
 
procedure LireListeDeMots;
var
  MotCour: string;
  lettre: char;
  fLex:   file;
  listeMots : TStringList;
begin
  TopChro := 0;
  TopChrono('');
  listeMots := TStringList.Create;
  AssignFile(fLex, 'liste.de.mots.francais.frgut.txt');
   {$I-}
  Reset(fLex, 1);
   {$I+}
  if IOResult = 0 then
  begin
    Seek(fLex, 0);
    MotCour := '';
    while not EOF(fLex) do
    begin
      BlockRead(fLex, lettre, 1);
      if lettre <> Chr(10) then
        MotCour := MotCour + lettre
      else
      begin
        listeMots.Append(MotCour);
        MotCour     := '';
      end;
    end;
    CloseFile(fLex);
    TopChrono('Lecture octets');
    Form1.Label1.Caption := 'Dernier mot (n° '
        + IntToStr(listeMots.Count) + ') : ' + listeMots.Strings[listeMots.Count-1];
  end
  else
    ShowMessage('Erreur d''accès au fichier');
  Beep;
end;
 
procedure LireListe2;
var
  MotCour: string;
  fLex:   TextFile;
  listeMots : TStringList;
begin
  TopChro := 0;
  TopChrono('');
  listeMots := TStringList.Create;
  AssignFile(fLex, 'liste.de.mots.francais.frgut.txt');
   {$I-}
  Reset(fLex);
   {$I+}
  if IOResult = 0 then
  begin
    while not EOF(fLex) do
    begin
      ReadLn(fLex, MotCour);
      listeMots.Append(MotCour);
    end;
    CloseFile(fLex);
    TopChrono('Lecture mots');
    Form1.Label1.Caption := 'Lecture par mot ; mot (n° '
        + IntToStr(listeMots.Count) + ') : ' + listeMots.Strings[listeMots.Count-1];
  end
  else
    ShowMessage('Erreur d''accès au fichier');
  Beep;
end;
 
procedure LireListeTexte;
var
  listeMots : TStringList;
begin
  TopChro := 0;
  TopChrono('');
  listeMots := TStringList.Create;
  listeMots.LoadFromFile('liste.de.mots.francais.frgut.txt');
  TopChrono('Lecture texte');
  Form1.Label1.Caption := 'Lecture 3 ; dernier mot (n° '
        + IntToStr(listeMots.Count) + ') : ' + listeMots.Strings[listeMots.Count-1];
  Beep;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
   LireListeDeMots;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  LireListe2;
end;
 
procedure TForm1.Button3Click(Sender: TObject);
begin
  LireListeTexte;
end;
 
initialization
  {$I uLex1.lrs}
 
end.

précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2014 dimanche2003. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.