Compression▲
Introduction▲
L'utilisation de Lazarus nous a permis d'accéder à une importante base de vocabulaire disponible sur Internet, de l'enrichir, d'établir des liens logiques, et de réaliser des recherches fructueuses dans l'optique de mots croisés.
Aux plans techniques ou ergonomiques, rien n'est parfait évidemment.
Nous allons ici examiner le cas des deux fichiers de données, l'un en mode texte qui regroupe tous les mots, l'autre en mode binaire qui reçoit les liens sous forme de tableaux de nombres. Ne serait-il pas plus simple - et plus sûr - de rassembler ces données dans un seul fichier ?
Par ailleurs, nous allons créer une boîte de dialogue autorisant une sélection : son intérêt immédiat est évident, et la méthode proposée, particulièrement simple, pourra recevoir de nombreuses applications.
Environnement▲
Chapitre 11…
Créons un répertoire Lex11 et recopions dans ce nouveau répertoire tous les fichiers du répertoire Lex10 utilisé précédemment. Pour éviter toute difficulté ultérieure, suivez la check-list :
- ouvrir pLex10.lpi dans Lex11 avec Lazarus ;
- enregistrer uLex10.pas sous le nom de uLex11.pas ;
- accepter la suppression des références à uLex10.pas ;
- enregistrer pLex10.pas sous le nom de pLex11.pas ;
- renommer la fenêtre Lex10 en Lex11 ;
- dans le répertoire Lex11 supprimer les anciens fichiers contenant la mention Lex10 ;
- dans la procédure MAJBalayage, remplacer Lex10 par Lex11.
Les fichiers de données (mots et liens) peuvent être téléchargés à l'aide du lien inclus dans le chapitre 9.
Nous retrouvons le projet dans l'état où nous l'avions laissé, et les modifications que nous allons apporter n'affecteront pas l'étape précédente consultable dans le répertoire Lex10.
Modification du stockage▲
L'ensemble de nos données est stocké sur disque sous forme de deux fichiers :
Nom | Taille (kOctets) |
LiMots.txt | 3Â 981 |
FichLiens.bin | 95 |
total | 4Â 076 |
Pour leur exploitation, les informations sont mises en mémoire dans les composants listeMots et Liens, qui sont respectivement une StringList et un tableau d'entiers (array of integer) dont les accès sont extrêmement rapides. Le point faible est évidemment le transfert du disque vers la mémoire et inversement.
Dans le deuxième chapitre, nous avons mesuré les vitesses d'accès au disque dans différents cas de figure : nous allons reprendre les outils et mesurer cette fois la durée de l'ensemble de la lecture et de l'enregistrement des fichiers.
Temps d'accès aux deux fichiers▲
Dans la liste des unités, nous ajoutons à nouveau un élément de la bibliothèque LCL, LclIntf, qui donne accès au compteur du processeur :
uses
Classes, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, ComCtrls, uDisque, LclIntf;
Dans les variables globales, nous ajoutons TopChro qui recevra la valeur du compteur au départ du chronomètre :
var
Form1: TForm1;
listeMots, listeInfo : TstringList;
iMot, nMots, nLiens, iLien, TopChro : integer
;
AffListe : TListBox;
Et nous recopions la procédure(44) TopChrono :
procedure
TForm1.TopChrono(Message
: string
);
begin
if
TopChro = 0
then
begin
TopChro := GetTickCount;
Form1.Memo1.Append(Message
);
end
else
Form1.Memo1.Append(Message
+ ' Durée '
+ IntToStr(GetTickCount-TopChro)+' ms'
);
end
;
Notre interface graphique comprend de nombreux onglets, dont le dernier, Fichier, qui est pratiquement vide. Nous y ajoutons un bouton (Caption modifié en « Chrono1 ») et un Memo :
Nous voulons provoquer la lecture et l'enregistrement des fichiers depuis un clic sur le bouton.
La procédure onClick de ce bouton peut s'écrire ainsi :
procedure
TForm1.Button4Click(Sender: TObject);
begin
TopChro := 0
;
TopChrono('Début processus'
);
LireFichier(ListeMots);
lireLiens;
regFichier(listeMots);
regLiens;
TopChrono('Fin processus'
);
end
;
Lançons l'exécution (petit triangle vert) ; clic sur le bouton Chrono1 : le mémo affiche le résultat de la mesure, soit 500 ms pour l'ensemble des processus de lecture et d'enregistrement des données.
Nous remarquons que le chargement de l'application et sa fermeture - enregistrement des données inclus - prennent au total un délai tout à fait acceptable compte tenu de la masse des informations traitées.
Les résultats peuvent varier sensiblement d'un ordinateur à un autre.
La valeur - purement indicative - sera réutilisée ultérieurement.
Fichier unique▲
Nous savons enregistrer du texte et, séparément, des tableaux de nombres de taille variable. L'emploi de l'instruction BlockWrite permet d'enregistrer toute donnée, en prenant soin de préciser au préalable sa taille : une chaîne de caractères de 7 signes sera enregistrée avec l'inscription de sa longueur -7- immédiatement avant. Un nombre quelconque sera enregistré selon la longueur qui doit être précisée : un octet sur une longueur de 1, un entier sera enregistré sur 4 octets, etc. Nous pouvons donc engager la séquence suivante :
- ouverture d'un fichier qui sera nommé Lex1.bin ;
- ouverture d'une boucle qui balaiera toute la liste de mots :
- pour chaque mot, enregistrement :
- de sa longueur,
- du mot proprement dit,
- de la taille du tableau de liens qui lui est associé,
- des liens éventuels.
- pour chaque mot, enregistrement :
- fermeture du fichier.
Le code de la procédure ecrireBase peut s'écrire ainsi :
procedure
ecrireBase;
var
i, j, k, m, nbOct, SLong: integer
;
Erreur: integer
;
Moti : string
;
begin
AssignFile(fLex, 'Lex1.bin'
); //==========nouveau fichier==============================
{$I-}
Reset(fLex, 1
);
{$I+}
Erreur := IOResult;
if
Erreur <> 0
then
ReWrite(fLex, 1
);
for
i := 0
to
listeMots.Count - 1
do
//champ par champ à coder (longueur)
begin
Moti := listeMots[i];
ecrireMot(Moti);
m := Form1.chercheTab(i); //présence de liens
if
m<0
then
j:=0
else
j:= Length(Liens[m]);
ecrireNombre(j, 4
);
if
j>0
then
for
k:= 0
to
j-1
do
ecrireNombre(Liens[m, k], 4
);
end
;
CloseFile(fLex);
end
;
À noter la variable globale fLex : file à créer en tête, juste après l'instruction uses :
implementation
uses
ulex11;
var
fLex : file
;
Deux procédures, ecrireMot et ecrireNombre, sont spécialisées dans les accès au disque :
procedure
ecrireMot(Moti : string
);
var
longMot : byte
;
nbOct: integer
;
begin
longMot := Length(Moti);
BlockWrite(fLex, longMot, SizeOf(longMot), nbOct);
BlockWrite(fLex, Moti[1
], longMot, nbOct);
end
;
procedure
ecrireNombre(var
k; longK: byte
);
var
nbOct : integer
;
begin
BlockWrite(fLex, k, longK, nbOct);
end
;
Un lecteur attentif aura remarqué que le nombre peut être enregistré sur une longueur qui sera fixée par paramètre (longK).
Par ailleurs, la variable nbOct reste inutilisée ici : elle serait utile pour analyser un éventuel problème lors des accès au disque.
Pour la lecture, nous reprenons la même méthode ; ne connaissant pas le nombre de mots, le programme va incrémenter une variable jusqu'à rencontrer la fin du fichier. Le code peut s'écrire ainsi :
procedure
lireBase;
var
i, j, k, iTab, nbOct, SLong: integer
;
Erreur: integer
;
begin
SetLength(Liens, 0
);
AssignFile(fLex, 'Lex1.bin'
); //=nouveau fichier==================
{$I-}
Reset(fLex, 1
);
{$I+}
Erreur := IOResult;
if
Erreur <> 0
then
ReWrite(fLex, 1
);
i:=0
;//indice du mot
iTab :=0
;//indice du tableau de liens
listeMots.Clear;
while
not
EOF(fLex) do
begin
listeMots.Append(Lire);
j := lireNombre(4
);
if
j>0
then
begin
SetLength(Liens, Length(Liens)+1
);
SetLength(Liens[iTab], j);
for
k:=0
to
j-1
do
Liens[iTab, k] := lireNombre(4
);
inc(iTab);
end
;
inc(i);
end
;
CloseFile(fLex);
end
;
Les accès disque sont réservés aux fonctions Lire et lireNombre :
function
lire: string
;
var
longMot : byte
;
nbOct: integer
;
S: string
;
begin
BlockRead(fLex, longMot, 1
, nbOct);
SetLength(S, longMot);
BlockRead(fLex, S[1
], longMot, nbOct);
lire := S;
end
;
function
lireNombre(i: byte
): integer
;
var
nbOct: integer
;
begin
BlockRead(fLex, Result, i, nbOct);
end
;
Il nous reste maintenant à évaluer le résultat.
Nous introduisons un nouveau bouton, propriété Caption « Chrono2 », et dans la procédure onClick de ce bouton nous déclenchons le chrono pour encadrer les tâches d'enregistrement et de lecture :
procedure
TForm1.Button5Click(Sender: TObject);
begin
TopChro := 0
;
TopChrono('Début processus'
);
ecrireBase;
lireBase;
TopChrono('Fin processus'
);
end
;
Un clic sur le petit triangle vert… un clic sur le bouton Chrono2… un peu de patience… et le résultat désastreux s'affiche :
La réunion des deux fichiers a multiplié le temps de chargement/déchargement par un facteur de 46 !
Voyons si ce délai peut être raccourci.
Compression des mots▲
Le nouveau fichier de données s'appelle Lex1.bin. Si l'on examine son contenu à l'aide d'un éditeur, Notepad++ par exemple, on constate une répétition systématique de portions de chaînes :
Après tout, pour stocker un mot, il suffit d'enregistrer la différence qu'il présente avec le mot précédent…
Nous créons donc la fonction compteLet, qui fixe le nombre de lettres à reprendre du mot précédent pour le début du mot d'indice i.
function
compteLet(MotPrec, Moti: string
): byte
;
var
i : byte
;
begin
i:= 1
;
while
(i<Length(MotPrec)) and
(i<Length(Moti))
and
(MotPrec[i] = Moti[i]) do
inc(i);
compteLet := i-1
;
end
;
Connaissant ce paramètre, nous pouvons remanier l'organigramme précédent pour l'intégrer lors de l'enregistrement :
- ouverture d'un fichier, qui sera nommé Lex2.bin ;
- ouverture d'une boucle qui balaiera toute la liste de mots :
- pour chaque mot, enregistrement :
- de sa longueur réduite à la partie droite différente par rapport au mot précédent,
- de cette partie proprement dite,
- du nombre de lettres à reprendre du mot précédent,
- de la taille du tableau de liens qui lui est associé,
- des liens éventuels.
- pour chaque mot, enregistrement :
- Fermeture du fichier.
La procédure ecrireMot devient ecrireZip :
procedure
ecrireZip;
var
i, j, k, m, nbOct : integer
;
nLiens, nLet : byte
;
Erreur: integer
;
S, MotPrec, Moti : string
;
begin
//nTotLiens := 0;
AssignFile(fLex, 'Lex2.bin'
); //==========nouveau fichier dico==============================
{$I-}
Reset(fLex, 1
);
{$I+}
Erreur := IOResult;
if
Erreur <> 0
then
ReWrite(fLex, 1
);
Truncate(fLex);
Seek(fLex, 0
);
MotPrec := ''
;
for
i := 0
to
listeMots.Count - 1
do
//champ par champ à coder (longueur)
begin
Moti := listeMots[i];
nLet := compteLet(MotPrec, Moti);
S := RightStr(Moti, Length(Moti)-nLet);
EcrireMot(S);
EcrireNombre(nLet, 1
); //nombre de lettres communes avec le préc
m := Form1.chercheTab(i); //présence de liens
if
m<0
then
nLiens:=0
else
nLiens:= Length(Liens[m]);
ecrireNombre(nLiens, 1
);
if
nLiens>0
then
for
k:= 0
to
nLiens-1
do
ecrireNombre(Liens[m, k], 4
);
MotPrec := Moti;
end
;
CloseFile(fLex);
end
;
Pour lire les données ainsi enregistrées, nous créons la procédure lireZip, qui accèdera aux données dans le même ordre :
procedure
lireZip;
var
longLiens, nLet : byte
;
i, j, k, iTab : integer
;
MotPrec, Moti : string
;
begin
AssignFile(fLex, 'LexLiens.bin'
);
{$I-}
Reset(fLex, 1
);
{$I+}
if
IOResult = 0
then
begin
Seek(fLex, 0
);
i := 0
;
listeMots.Clear;
SetLength(Liens, 0
);
iTab := 0
;
MotPrec := ''
;
while
not
EOF(fLex) do
begin
Moti := Lire;
nLet := LireNombre(1
); //nombre de lettres à reprendre du précédent
Moti := LeftStr(MotPrec, nLet) + Moti;
listeMots.Append(Moti);
MotPrec := Moti; //
longLiens := lireNombre(1
);
if
longLiens>0
then
begin
SetLength(Liens, Length(Liens)+1
);
SetLength(Liens[iTab], longLiens);
for
k:=0
to
longLiens-1
do
Liens[iTab, k] := lireNombre(4
);
inc(iTab);
end
;
Inc(i);
end
;
nLiens := iTab;
CloseFile(fLex);
end
;
end
;
Pour évaluer l'efficacité de la méthode, nous mesurons la durée de l'enregistrement et de la lecture des données.
Dans l'onglet Fichier, nous ajoutons un bouton, Caption « Chrono3 », et dans la procédure onClick de ce bouton, nous complétons le code comme précédemment :
procedure
TForm1.Button11Click(Sender: TObject);
begin
TopChro := 0
;
TopChrono('Début processus'
);
ecrireZip;
lireZip;
TopChrono('Fin processus'
);
end
;
Un clic sur le petit triangle vert pour lancer l'exécution, un clic sur le nouveau bouton, et le verdict apparaît :
Mode retenu▲
Sans appel : nos manœuvres aboutissent à des résultats rédhibitoires, et la solution antérieure se révèle nettement supérieure aux variantes envisagées. Nous avions déjà eu l'occasion de signaler la puissance de la fonction précâblée autorisant la lecture d'un texte en une seule fois, et nous constatons encore son efficacité.
Fichiers de données | Volume (KO) | Durée Entrée/Sortie (ms) |
LiMots.txt + fichLiens.bin | 4Â 076 | 500 |
Lex1.bin | 5Â 043 | 23Â 125 |
Lex2.bin | 1Â 888 | 28Â 156 |
Pourtant, la compacité du fichier zip obtenu (1,9 Mo) présente un certain intérêt : pourquoi ne pas adopter ce format pour sauvegarder les données et les restaurer en cas de problème ?
Le lecteur avisé remplacera les boutons Chrono par un bouton de sauvegarde, et un second destiné à la restauration. Le format de fichier sera évidemment celui qui donne le volume le plus réduit.
Ainsi, il sera armé en cas de problème sur l'un ou l'autre des fichiers de données.
Le troisième bouton pourra être supprimé de l'onglet ainsi que le composant Memo.
Pour revenir aux accès-fichiers antérieurs, nous réactivons les instructions LireFichier et LireLiens dans la procédure FormCreate, et regLiens, regFichier dans la procédure Button1Click.
Fenêtre de choix▲
Les boîtes de dialogue offertes par Lazarus sont pratiques, mais leurs performances souvent limitées.
Par exemple, si un utilisateur frappe le mot « macon », notre logiciel fait apparaître une fenêtre de confirmation qui présente bien les mots proches existants, et le choix Yes/No. Le signe point d'interrogation ne présente aucun intérêt, de même que la croix de fermeture.
Nous nous proposons ici de créer une boîte de dialogue dans laquelle l'utilisateur pourra cliquer sur un des mots présentés en alternative, pour le sélectionner, et avec un libellé des boutons plus précis.
Principe de fonctionnement▲
Pour créer une fenêtre de dialogue, nous disposons des fonctions Hide, Show, Activate, Visible, etc. qui permettent d'afficher et de cacher une fenêtre. L'ensemble devient rapidement lourd et complexe.
Pourtant, la tâche devient très simple en utilisant la variable ModalResult liée à chaque fenêtre.
La procédure est la suivante :
- ajouter au projet une nouvelle fiche ;
- la nouvelle fiche est affectée automatiquement d'une variable cachée, ModalResult(45), dont la valeur initiale est fixée à zéro ;
- aussitôt que, dans le cadre d'un événement quelconque, cette variable reçoit une nouvelle valeur (donc différente de zéro), la nouvelle fiche est cachée ;
- la valeur de la variable est récupérable dans la fenêtre principale (ou toute autre fenêtre du projet) sous le nom de ShowModal.
Par exemple, dans la nouvelle fenêtre Form2, nous introduisons un bouton, et dans la procédure onClick de ce bouton, nous écrivons l'instruction unique :
ModalResult:= 333
;
Aussitôt que l'on aura cliqué sur le bouton, la nouvelle fenêtre disparaîtra. Pour récupérer la valeur de ModalResult dans la variable i, il suffira d'écrire l'instruction :
I := Form2.ShowModal ;
Fenêtre modale▲
Dans le menu de Lazarus, nous cliquons sur le mot Fichier et choisissons Nouvelle Fiche. L'objet apparaît sur le bureau, complété dans l'éditeur de source par une nouvelle unité que nous enregistrons sous le nom de uDialog.
Déclarations▲
Cette unité est déclarée à la suite des autres dans la ligne Uses de uLex11 :
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, ComCtrls, uDisque, uDialog;
Par ailleurs, dans l'unité uDialog, nous déclarons l'unité principale uLex11, sous le mot-clé implementation :
implementation
uses
uLex11;
{ TForm2 }
Interface graphique▲
Nous titrons la fenêtre (propriété Caption) en « Choix du mot » et nous lui ajoutons quatre composants :
- un ListBox, qui recevra le mot nouveau et les mots approchants éventuels ;
- un Label qui affichera le mot sélectionné ;
- un bouton (Caption porté à « Confirmer ») ;
- un second bouton, « Abandon ».
Les dispositions sont ajustées à la souris pour obtenir sensiblement ceci :
Pour supprimer les icônes techniques, nous portons à False toutes les valeurs des lignes de BorderIcons dans l'inspecteur d'objets. Au sujet de l'encadrement de la fenêtre, nous choisissons bsDialog dans la ligne BorderStyle.
Code▲
La procédure Choix affichera dans le ListBox le mot nouveau, transmis en paramètre, suivi de tous les mots approchants. Sa déclaration se fait à la suite des composants. Un appui sur les touches Ctrl + Maj + C créent la nouvelle structure, que nous complétons ainsi :
procedure
TForm2.Choix(motNouv: string
);
var
i : integer
;
begin
Label1.Caption:=AnsiToUTF8(motNouv);
ListBox1.Clear;
ListBox1.Items.Append(Label1.Caption);
ListBox1.Selected[0
] := True
;
iProv := -1
;
if
Length(tabApprox) > 0
then
for
i:= 0
to
Length(tabApprox)-1
do
ListBox1.Items.Append(AnsiToUTF8(listeMots[tabApprox[i]]));
end
;
La variable provisoire iProv recevra les indices des mots choisis ; au départ, elle vaut -1, ce qui exprime que le mot sélectionné est le mot nouveau. Cette variable sera modifiée dans d'autres procédures : il faut donc la déclarer en variable globale.
var
Form2: TForm2;
iProv : integer
;
implementation
uses
uLex11;
{ TForm2 }
Pour modifier la sélection, nous utilisons l'événement onClick du listBox :
procedure
TForm2.ListBox1Click(Sender: TObject);
begin
Label1.Caption:= ListBox1.GetSelectedText;
if
ListBox1.ItemIndex>0
then
iProv := tabApprox[ListBox1.ItemIndex-1
]
else
iProv := -1
;
end
;
Pour confirmer le choix, nous cliquons sur le premier bouton ; la procédure onClick s'écrit simplement ainsi :
procedure
TForm2.Button1Click(Sender: TObject);
begin
ModalResult := iProv;
end
;
Et pour abandonner, un clic sur le 2e bouton déclenchera la procédure suivante :
procedure
TForm2.Button2Click(Sender: TObject);
begin
ModalResult := -2
;
end
;
Ouverture du dialogue▲
Jusqu'à présent, la boîte de dialogue s'ouvrait dans le cours de la fonction fAnnonceMotNouveau : nous la remanions pour lancer la procédure Choix et récupérer la valeur de ShowModal.
function
TForm1.fAnnonceMotNouveau(motNouv: string
): integer
;
var
i, indexMotNouv : integer
;
begin
Form2.Choix(motNouv);
i := Form2.ShowModal;
Case
i of
-2
: ShowMessage('Abandon'
);
-1
: begin
indexMotNouv := fMotNouv(motNouv);
AjoutMot(motNouv, indexMotNouv);
fAnnonceMotNouveau := indexMotNouv;
end
;
else
begin
fAnnonceMotNouveau := i;
Edit3.Caption := AnsiToUTF8(listeMots[i]);
end
;
end
;
end
;
Application▲
Nous allons tester notre nouvelle boîte de dialogue en entrant le nom de Pâris, qui est le fils de Priam, roi de Troie. Dans l'onglet Liens, nous écrivons « Pâris » et cliquons sur la flèche vers le haut : notre nouvelle fenêtre de dialogue apparaît.
À cet instant, l'utilisateur aura la possibilité de sélectionner un des deux autres mots, de changer d'avis, et enfin de confirmer son choix ou d'abandonner. Dès qu'il aura pris sa décision (un clic sur un bouton est nécessaire), la fenêtre de dialogue disparaîtra et la gestion habituelle de notre dictionnaire pourra reprendre.
Il semble que l'ergonomie de notre projet se soit nettement améliorée… mais incontestablement, il reste encore à faire pour le mettre à l'abri de toute critique !
Conclusion▲
Ce chapitre nous a montré comment stocker et sauvegarder nos données de façon efficace : rapide pour un accès courant, compacte pour des sauvegardes de sécurité. Nous avons laissé au lecteur le soin de nettoyer le dernier onglet pour ne laisser, outre le bouton Arrêt, que les boutons Sauvegarde et Récupération.
Par ailleurs, nous avons réalisé une boîte de dialogue personnalisée qui améliore l'assistance de l'utilisateur lorsqu'il entre un mot nouveau. La programmation se révèle particulièrement simple et le résultat convaincant.
Notre projet tient maintenant la route et nous espérons qu'il sera utile à de nombreux cruciverbistes et… aux apprentis programmeurs, qui peuvent constater ici que l'informatique peut - aussi - aborder des domaines aussi complexes que le vocabulaire, l'orthographe, et… l'association d'idées.
Cédille Signe typographique inventé par un certain M. Duçon. |
Code▲
Unité uLex11▲
unit
ulex11;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, ComCtrls, uDisque, uDialog;
type
{ TForm1 }
TForm1 = class
(TForm)
Button1: TButton;
Button10: TButton;
Button11: TButton;
Button12: TButton;
Button2: TButton;
Button3: TButton;
boutFH: TButton;
boutReq: TButton;
boutMasq: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Button7: TButton;
Button8: TButton;
Button9: TButton;
CheckBox1: TCheckBox;
edMasq: TEdit;
edReq: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
labMasq: TLabel;
labReq: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
ListBox1: TListBox;
ListBox2: TListBox;
ListBox3: TListBox;
ListBox4: TListBox;
lisReq: TListBox;
lisMasq: TListBox;
Memo1: TMemo;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;
RadioButton4: TRadioButton;
TabSheet3: TTabSheet;
TabSheet4: TTabSheet;
TabSheet5: TTabSheet;
TabSheet6: TTabSheet;
tabLogique: TTabSheet;
Zoom: TGroupBox;
Label1: TLabel;
Label2: TLabel;
AffListe: TListBox;
PageControl1: TPageControl;
Page1: TTabSheet;
TabSheet1: TTabSheet;
TrackBar1: TTrackBar;
UpDown2: TUpDown;
procedure
AffListeClick(Sender: TObject);
procedure
boutFHClick(Sender: TObject);
procedure
boutMasqClick(Sender: TObject);
procedure
boutReqClick(Sender: TObject);
procedure
Button10Click(Sender: TObject);
procedure
Button11Click(Sender: TObject);
procedure
Button12Click(Sender: TObject);
procedure
Button1Click(Sender: TObject);
procedure
Button2Click(Sender: TObject);
procedure
Button3Click(Sender: TObject);
procedure
Button4Click(Sender: TObject);
procedure
Button5Click(Sender: TObject);
procedure
Button6Click(Sender: TObject);
procedure
Button7Click(Sender: TObject);
procedure
Button8Click(Sender: TObject);
procedure
Button9Click(Sender: TObject);
procedure
CheckBox1Change(Sender: TObject);
procedure
FormCreate(Sender: TObject);
procedure
ListBox1Click(Sender: TObject);
procedure
ListBox2Click(Sender: TObject);
procedure
ListBox3Click(Sender: TObject);
procedure
ListBox4Click(Sender: TObject);
procedure
Recherche(rechMot: string
);
procedure
tabLogiqueExit(Sender: TObject);
procedure
tabLogiqueShow(Sender: TObject);
procedure
TabSheet1Show(Sender: TObject);
procedure
TabSheet3Show(Sender: TObject);
procedure
TabSheet4Show(Sender: TObject);
procedure
TabSheet5Show(Sender: TObject);
procedure
TrackBar1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer
);
procedure
MAJBalayage;
procedure
UpDown2Click(Sender: TObject; Button: TUDBtnType);
procedure
ZoomMouseLeave(Sender: TObject);
function
chercheTab(iMot : integer
) : integer
;
procedure
Lier(iMot, iLien : integer
);
procedure
AffLiens;
procedure
PlaceLien(k : integer
);
function
PlaceTab(k : integer
) : integer
;
function
SansAccent(rMot : string
) : string
;
procedure
listeApprox(rechMot : string
);
procedure
MAJSupp;
procedure
SuppLien(iMot, iLien : integer
);
function
fMotNouv(rechMot : string
) : integer
;
function
fAnnonceMotNouveau(motNouv : string
) : integer
;
procedure
AjoutMot(motNouv : string
; indexMotNouv : integer
);
procedure
AjoutMotSecur(motNouv : string
; indexMotNouv : integer
);
procedure
SupMot(motCour : string
; indexMotCour : integer
);
function
fDoublon(iMot, iLien: integer
): boolean
;
procedure
Masque(rechMot: string
);
procedure
AjoutOccur(iOccur : integer
);
procedure
TriOccur;
private
{ private declarations }
public
{ public declarations }
end
;
const
delta=5
;
var
Form1: TForm1;
listeMots, listeInfo : TstringList;
iMot, nMots, nLiens, iLien : integer
;
AffListe : TListBox;
Liens : Array
of
Array
of
integer
;
tabApprox, tabReq, tabOccur : Array
of
integer
; //index des mots approchants
sAcc, cAcc : string
;
implementation
{$R *.lfm}
{ TForm1 }
procedure
TForm1.Button1Click(Sender: TObject);
begin
regLiens;
regFichier(listeMots);
//regMotsLiens;
listeMots.Free;
Application.Terminate;
end
;
procedure
TForm1.AffListeClick(Sender: TObject);
begin
iMot := (iMot -delta + AffListe.ItemIndex + nMots) mod
nMots;
MAJBalayage;
end
;
procedure
TForm1.boutFHClick(Sender: TObject);
var
i, j, k : integer
;
begin
//ajoute un mot à la liste de base tabReq
i := listeMots.IndexOf(UTF8ToAnsi(edReq.Caption));
if
i>=0
then
//le mot existe dans la liste principale
begin
j:=0
;
k := Length(tabReq);
while
(j<k) and
(i<>tabReq[j]) do
inc(j);
if
j=k then
//le mot peut être ajouté
begin
SetLength(tabReq, k+1
); //ajoute une unité au tableau
tabReq[k] := i;
//affichage de la requête dans la ligne titre
if
labReq.Caption = 'Requête '
then
labReq.Caption:= edReq.Caption //premier mot-clé
else
labReq.Caption:= labReq.Caption +' + '
+edReq.Caption;
end
;
end
;
edReq.Clear;
end
;
procedure
TForm1.boutMasqClick(Sender: TObject);
var
i, j, k : integer
;
motCour, sMasque : string
;
begin
i := 0
;
sMasque := edMasq.Caption;
k := Length(sMasque);
lisMasq.Clear;
repeat
motCour := SansAccent(listeMots[tabOccur[i]]);
if
Length(motCour) = k then
//balayage du mot pour comparaison des lettres
begin
j := 1
;
while
(j<=k) and
((sMasque[j]='$'
) or
(sMasque[j] = motCour[j])) do
inc(j);
if
j>k then
lisMasq.Items.Append(AnsiToUTF8(listeMots[tabOccur[i]]));
end
;
inc(i);
until
(i=Length(tabOccur));
end
;
procedure
TForm1.boutReqClick(Sender: TObject);
const
profRech = 2
; //fixe la profondeur de la recherche
var
i, j, k, n : integer
;
begin
if
Length(tabReq)>0
then
//la requête ne doit pas être vide
begin
for
n := 1
to
profRech do
begin
SetLength(tabOccur, 0
);
for
i:=0
to
Length(tabReq)-1
do
begin
j := 0
;
while
(j<Length(Liens)) and
(Liens[j, 0
]<>tabReq[i])do
inc(j);
if
j<Length(Liens) then
for
k:=1
to
Length(Liens[j])-1
do
AjoutOccur(Liens[j, k]);
end
;
tabReq := tabOccur;
end
;
j := Length(tabOccur);
//afficher les occurrences et leur nombre
lisReq.Items.Append(IntToStr(j)+' occurrences : '
);
TriOccur; //trier avant affichage
for
i:=0
to
j-1
do
lisReq.Items.Append(AnsiToUTF8(listeMots[tabOccur[i]]));
end
;
edMasq.Clear;
edMasq.Visible:=True
;
labMasq.Visible:=True
;
lisMasq.Visible:=True
;
boutMasq.Enabled:=True
;
end
;
procedure
TForm1.Button10Click(Sender: TObject);
var
iLien : integer
;
motNouv : string
;
begin
if
Edit3.Caption > #47
then
begin
motNouv := UTF8ToAnsi(Edit3.Caption);
iLien := listeMots.IndexOf(motNouv);
if
iLien<0
then
iLien := fAnnonceMotNouveau(motNouv);
//iLien vaut maintenant l'index du mot nouveau ou approché
if
(iLien>=0
) and
(iLien<>iMot) and
not
fDoublon(iMot, iLien) then
begin
Label4.Caption:= Edit3.Caption;
iMot := iLien;
end
;
AffLiens;
end
else
ShowMessage('Entrez le mot'
);
Edit3.Clear;
end
;
procedure
TForm1.Button11Click(Sender: TObject);
begin
//regMotCourtsLiens;
ecrirebase;
end
;
procedure
TForm1.Button12Click(Sender: TObject);
begin
//LireMotCourtsLiens;
lirebase;
end
;
procedure
TForm1.Button2Click(Sender: TObject);
begin
//Recherche(UTF8ToAnsi(Edit2.Caption));
ListBox3.Clear;
Masque(SansAccent(UTF8ToAnsi(Edit2.Caption)));
end
;
function
TForm1.fMotNouv(rechMot: string
): integer
;
var
i, k : integer
;
referMot : string
;
begin
SetLength(tabApprox, 0
); //mise à zéro du tableau
referMot := SansAccent(rechMot);
//point de démarrage de la recherche : première lettre du mot
i := 0
;
k := 0
;
while
SansAccent(listeMots[i][1
]) < referMot[1
] do
inc(i);
//début de la recherche
repeat
//k index futur du mot nouveau
if
(k=0
) and
(SansAccent(listeMots[i]) > referMot) then
k := i
else
if
SansAccent(listeMots[i]) = referMot then
begin
//enregistrement des index pour réutilisation
SetLength(tabApprox, Length(tabApprox)+1
);
tabApprox[Length(tabApprox)-1
] := i;
end
;
inc(i)
until
(i>nMots-1
) or
(SansAccent(listeMots[i][1
]) > referMot[1
]);
if
k=0
then
fMotNouv := nMots else
fMotNouv := k;
end
;
//==========================
function
TForm1.fAnnonceMotNouveau(motNouv: string
): integer
;
var
i, indexMotNouv : integer
;
begin
Form2.Choix(motNouv);
i := Form2.ShowModal;
Case
i of
-2
: ShowMessage('Abandon'
);
-1
: begin
indexMotNouv := fMotNouv(motNouv);
AjoutMot(motNouv, indexMotNouv);
fAnnonceMotNouveau := indexMotNouv;
end
;
else
begin
fAnnonceMotNouveau := i;
Edit3.Caption := AnsiToUTF8(listeMots[i]);
end
;
end
;
end
;
procedure
TForm1.AjoutMot(motNouv: string
; indexMotNouv: integer
);
var
nouvLiens : array
of
array
of
integer
;
i, j : integer
;
begin
nouvLiens := Liens;
for
i:=0
to
Length(Liens)-1
do
for
j:=0
to
Length(Liens[i])-1
do
if
Liens[i, j]>= indexMotNouv then
inc(Liens[i, j]);
if
iMot >= indexMotNouv then
inc(iMot); //mise à jour effectuée
SetLength(nouvLiens, 0
);
listeMots.Insert(indexMotNouv, motNouv); //modification de la liste principale
inc(nMots);
end
;
//===========doublons=======================
function
TForm1.fDoublon(iMot, iLien: integer
): boolean
;
var
i, j : integer
;
begin
//vérfie que le lien n'existe pas déjÃ
//cherche le tableau de liens correspondant à iMot
fDoublon := False
;
j := chercheTab(iMot);
if
j>=0
then
begin
i := Length(Liens[j])-1
;
while
(i>0
) and
(iLien<Liens[j, i]) do
dec(i);
if
iLien = Liens[j, i] then
fDoublon := True
;
if
fDoublon then
ShowMessage('Doublon refusé'
);
end
;
end
;
procedure
TForm1.Masque(rechMot: string
);
var
i, j, k : integer
;
motCour : string
;
begin
i := 0
;
k := Length(rechMot);
Label1.Caption:= ('Mot de '
+ IntToStr(k)+ ' lettres'
);
ListBox3.Clear;
repeat
motCour := SansAccent(listeMots[i]);
if
Length(motCour) = k then
//balayage du mot pour comparaison des lettres
begin
j := 1
;
while
(j<=k) and
((rechMot[j]='$'
) or
(rechMot[j] = motCour[j])) do
inc(j);
if
j>k then
ListBox3.Items.Append(AnsiToUTF8(listeMots[i]));
end
;
inc(i);
until
(i=nMots) or
((rechMot[1
]='$'
) and
(rechMot[1
] > motCour[1
]));
//balayage tant que la première lettre est inférieure à celle du masque
if
ListBox3.Count=0
then
Label1.Caption:= ('échec'
)
else
Label1.Caption:= (IntToStr(ListBox3.Count)+
' mots trouvés'
);
end
;
procedure
TForm1.AjoutOccur(iOccur: integer
);
var
i : integer
;
begin
//vérifier que cette occurrence n'a pas encore été rencontrée
i:=0
;
while
(i<Length(tabOccur)) and
(iOccur<> tabOccur[i]) do
inc(i);
if
i= Length(tabOccur) then
//première occurrence du mot
begin
SetLength(tabOccur, i+1
);
tabOccur[i] := iOccur;
end
;
end
;
procedure
TForm1.TriOccur;
var
i, j, occTampon : integer
;
triOK : boolean
;
begin
i := 0
;
j := Length(tabOccur)-2
;
triOK := True
;
repeat
if
(tabOccur[i] > tabOccur[i+1
]) then
begin
occTampon := tabOccur[i];
tabOccur[i] := tabOccur[i+1
];
tabOccur[i+1
] := occTampon;
triOK := False
;
end
;
inc(i);
if
not
triOK and
(i>j) then
begin
i:=0
; //nouvelle passe de permutations
triOK:= True
;
end
;
until
triOK and
(i>j);
end
;
procedure
TForm1.AjoutMotSecur(motNouv: string
; indexMotNouv: integer
);
var
nouvLiens : array
of
array
of
integer
;
i, j : integer
;
begin
SetLength(nouvLiens, Length(Liens));
for
i:=0
to
Length(Liens)-1
do
begin
SetLength(nouvLiens[i], Length(Liens[i]));
for
j:=0
to
Length(Liens[i])-1
do
if
Liens[i, j]>= indexMotNouv then
nouvLiens[i, j] := Liens[i, j] + 1
else
nouvLiens[i, j] := Liens[i, j];
end
;
Liens := nouvLiens; //mise à jour effectuée
if
iMot >= indexMotNouv then
inc(iMot);
listeMots.Insert(indexMotNouv, motNouv); //modification de la liste principale
inc(nMots);
end
;
//==============================
procedure
TForm1.SupMot(motCour: string
; indexMotCour: integer
);
var
nouvLiens : array
of
array
of
integer
;
i, j : integer
;
begin
SetLength(nouvLiens, Length(Liens));
for
i:=0
to
Length(nouvLiens)-1
do
begin
SetLength(nouvLiens[i], Length(Liens[i]));
for
j:=0
to
Length(nouvLiens[i])-1
do
if
Liens[i, j]>= indexMotCour then
nouvLiens[i, j] := Liens[i, j] - 1
else
nouvLiens[i, j] := Liens[i, j];
end
;
if
iMot >= indexMotCour then
dec(iMot);
Liens := nouvLiens;
//mise à jour effectuée
listeMots.Delete(indexMotCour); //modification de la liste principale
dec(nMots);
end
;
procedure
TForm1.Button3Click(Sender: TObject);
var
iLien : integer
;
motNouv : string
;
begin
if
Edit3.Caption > #47
then
begin
motNouv := UTF8ToAnsi(Edit3.Caption);
iLien := listeMots.IndexOf(motNouv);
if
iLien<0
then
iLien := fAnnonceMotNouveau(motNouv);
if
(iLien>=0
) and
(iLien<>iMot) and
not
fDoublon(iMot, iLien) then
begin
Lier(iMot, iLien);
Lier(iLien, iMot);
end
;
AffLiens;
end
else
ShowMessage('Entrez le mot'
);
Edit3.Clear;
end
;
procedure
TForm1.Button4Click(Sender: TObject);
begin
uDisque.regMotsLiens;
end
;
procedure
TForm1.Button5Click(Sender: TObject);
begin
lireMotsLiens;
end
;
procedure
TForm1.Button6Click(Sender: TObject);
begin
SuppLien(iMot, iLien);
SuppLien(iLien, iMot);
end
;
//=================
procedure
TForm1.Button7Click(Sender: TObject);
var
i : integer
;
motNouv : string
;
begin
motNouv := UTF8ToAnsi(Edit4.Caption);
i := listeMots.IndexOf(motNouv);
if
(i >= 0
) then
ShowMessage('Mot existant'
)
else
begin
i := fAnnonceMotNouveau(motNouv);
if
i>=0
then
iMot := i;
Edit4.Clear;
end
;
end
;
procedure
TForm1.Button8Click(Sender: TObject);
var
indexMotCour : integer
;
motCour, Rep : string
;
begin
//le mot peut être supprimé si aucun lien ne lui est affecté
motCour := UTF8ToAnsi(Edit4.Caption);
indexMotCour := listeMots.IndexOf(motCour);
if
(indexMotCour<0
) then
ShowMessage ('Supprimé'
)
else
if
(chercheTab(indexMotCour)<0
) then
begin
Rep := 'Supprimer le mot '
+ Edit4.Caption +' ? '
;
if
MessageDlg ('Suppression'
, Rep, mtConfirmation,
[mbYes, mbNo],0
) = mrYes
then
SupMot(motCour, indexMotCour);
MAJBalayage;
Edit4.Clear;
end
else
ShowMessage ('Supprimez les liens avant de supprimer le mot'
);
end
;
procedure
TForm1.Button9Click(Sender: TObject);
begin
ShowMessage('Supprimez le mot, puis ajoutez le nouveau mot'
);
end
;
procedure
TForm1.CheckBox1Change(Sender: TObject);
begin
if
CheckBox1.Checked then
CheckBox1.Caption := 'Avec filtre'
else
CheckBox1.Caption := 'Sans filtre'
;
end
;
procedure
TForm1.FormCreate(Sender: TObject);
begin
listeMots := TStringList.Create;
listeMots.CaseSensitive:=True
;
//LireFichier(listeMots);
//lireLiens;
lireMotsLiens;
//lirebase;
nMots := listeMots.Count;
iMot := 0
;
Edit3.Clear;
Edit2.Clear;
Label1.Caption := 'saisir les lettres séparées par le signe $'
;
MAJBalayage;
cAcc := UTF8ToAnsi('à âäéèêëïîôùûüÿç-'' '
);
//regroupe tous les caractères à remplacer
sAcc := 'aaaeeeeiiouuuyc'
;
//regroupe tous les caractères de substitution
end
;
procedure
TForm1.ListBox1Click(Sender: TObject);
begin
If
ListBox1.ItemIndex >= 0
then
begin
iMot := Liens[chercheTab(iMot), ListBox1.ItemIndex+1
];
Label4.Caption := AnsiToUTF8(listeMots[iMot]);
AffLiens;
end
;
end
;
procedure
TForm1.ListBox2Click(Sender: TObject); //couleur $00C1FFDC
begin
If
ListBox2.ItemIndex >= 0
then
begin
iMot := Liens[chercheTab(iMot), ListBox2.ItemIndex+1
];
MAJBalayage;
end
;
end
;
procedure
TForm1.ListBox3Click(Sender: TObject);
begin
if
ListBox3.ItemIndex>=0
then
begin
iMot := listeMots.IndexOf(ListBox3.Items[ListBox3.ItemIndex]);
Label1.Caption:= listeMots[iMot];
end
;
end
;
procedure
TForm1.ListBox4Click(Sender: TObject);
begin
if
ListBox4.ItemIndex >= 0
then
begin
iLien := Liens[chercheTab(iMot), ListBox4.ItemIndex+1
];
Label6.Caption:= 'Supprimer le lien entre '
+
AnsiToUTF8(listeMots[iMot]) + ' et '
+
AnsiToUTF8(listeMots[iLien])+ ' ?'
;
Button6.Enabled := True
;
end
;
end
;
procedure
TForm1.MAJBalayage;
var
i : integer
;
begin
Label2.Caption:=AnsiToUTF8(listeMots[iMot]);
Label4.Caption:=Label2.Caption;
TrackBar1.Position:= Round(iMot*1000
/nMots);
Edit2.Clear;
AffListe.Clear;
for
i := 0
to
10
do
AffListe.Items.Add(AnsiToUTF8(listeMots[(iMot-5
+ i + nMots) mod
nMots]));
AffListe.Selected[5
] := True
;
AffLiens;
Caption := 'Lex11 '
+IntToStr(nMots)+ ' mots dont '
+IntToStr(nLiens) + ' liés'
;
MAJSupp;
end
;
procedure
TForm1.UpDown2Click(Sender: TObject; Button: TUDBtnType);
begin
if
CheckBox1.Checked then
repeat
inc(iMot);
until
(chercheTab(iMot)>=0
) or
(iMot=nMots)
else
if
Button=btNext then
Inc(iMot, UpDown2.Increment)
else
Dec(iMot, UpDown2.Increment);
iMot := (iMot + nMots) mod
(nMots);
MAJBalayage;
end
;
procedure
TForm1.ZoomMouseLeave(Sender: TObject);
begin
if
RadioButton1.Checked then
UpDown2.Increment := 1
else
if
RadioButton2.Checked then
UpDown2.Increment := 10
else
if
RadioButton3.Checked then
UpDown2.Increment := 100
else
if
RadioButton4.Checked then
UpDown2.Increment := 1000
;
end
;
function
TForm1.chercheTab(iMot: integer
): integer
;
var
i : integer
;
begin
chercheTab := -1
;
i := 0
;
while
(i<Length(Liens)) and
(Liens[i, 0
]<>iMot)do
inc(i);
if
i<Length(Liens) then
chercheTab := i;
end
;
procedure
TForm1.Lier(iMot, iLien: integer
);
var
k : integer
;
begin
k := chercheTab(iMot);
if
k < 0
then
begin
SetLength(Liens, Length(Liens)+1
); //extension du tableau principal
k := Length(Liens)-1
;
SetLength(Liens[k], 1
);
Liens[k][0
] := iMot; //identifiant
k := PlaceTab(k); //nouvel emplacement
Inc(nLiens); //mise à jour du nombre de mots liés
end
;
SetLength(Liens[k], Length(Liens[k])+1
); //extension du tableau secondaire
Liens[k, Length(Liens[k])-1
] := iLien; // lien
PlaceLien(k); //tri
end
;
procedure
TForm1.AffLiens;
var
i, k : integer
;
begin
if
Length(Liens)>0
then
begin
ListBox1.Clear;
k := chercheTab(iMot);
if
k>=0
then
for
i :=1
to
Length(Liens[k]) -1
do
ListBox1.Items.Add(AnsiToUTF8(listeMots[Liens[k, i]]));
ListBox2.Items := ListBox1.Items;
end
;
end
;
procedure
TForm1.PlaceLien(k: integer
);
var
i, Tamp : integer
;
begin
i := Length(Liens[k]) - 1
;
while
(Liens[k, i] < Liens[k, i-1
]) and
(i>1
) do
begin
Tamp := Liens[k, i];
Liens[k, i] := Liens[k, i-1
];
Liens[k, i-1
] := Tamp;
Dec(i);
end
;
end
;
function
TForm1.PlaceTab(k: integer
): integer
;
var
i : integer
;
Tamp : Array
of
integer
;
begin
i := k;
while
(Liens[i, 0
] < Liens[i-1
, 0
]) and
(i>1
) do
begin
Tamp := Liens[i];
Liens[i] := Liens[i-1
];
Liens[i-1
] := Tamp;
dec(i);
end
;
PlaceTab := i;
end
;
function
TForm1.SansAccent(rMot: string
): string
;
var
i, j : integer
;
//les variables sAcc et cAcc sont créées au démarrage
begin
SansAccent := ''
;
rMot := LowerCase(rMot);
for
i:=1
to
Length(rMot) do
begin
j := Pos(rMot[i], cAcc);
case
j of
0
: SansAccent := SansAccent + rMot[i];
1
..15
: SansAccent := SansAccent + sAcc[j];
end
;
end
;
end
;
procedure
TForm1.listeApprox(rechMot: string
);
var
i : integer
;
referMot : string
;
begin
SetLength(tabApprox, 0
); //mise à zéro du tableau
referMot := SansAccent(rechMot);
if
referMot>''
then
begin
//point de démarrage de la recherche : première lettre du mot
i := 0
;
while
SansAccent(listeMots[i][1
]) < referMot[1
] do
inc(i);
//début de la recherche
repeat
if
SansAccent(listeMots[i]) = referMot then
begin
listBox3.Items.Append(AnsiToUTF8(listeMots[i]));
//enregistrement des index pour réutilisation
SetLength(tabApprox, Length(tabApprox)+1
);
tabApprox[Length(tabApprox)-1
] := i;
end
;
inc(i)
until
(i>nMots-1
) or
(SansAccent(listeMots[i][1
]) > referMot[1
]);
//la première lettre a changé
end
;
end
;
procedure
TForm1.MAJSupp;
begin
Label5.Caption := Label4.Caption;
ListBox4.Items := ListBox1.Items;
Label6.Caption:= ''
;
Button6.Enabled:= False
;
end
;
procedure
TForm1.SuppLien(iMot, iLien: integer
);
var
i, k : integer
;
begin
//dans le tableau secondaire de iMot, on supprime iLien
k := chercheTab(iMot);
i:=1
;
while
Liens[k, i]<> iLien do
inc(i);
while
(i<Length(Liens[k])-1
) do
begin
Liens[k, i] := Liens[k, i+1
];
inc(i);
end
;
SetLength(Liens[k], Length(Liens[k]) - 1
);
if
(Length(Liens[k]) = 1
) then
//le mot n'a plus de lien
begin
for
i := k to
Length(Liens)-2
do
Liens[i] := Liens[i+1
];
SetLength(Liens, Length(Liens)-1
);
nLiens := Length(Liens);
end
;
MAJBalayage;
end
;
procedure
TForm1.TrackBar1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer
);
begin
iMot := Round(TrackBar1.Position*nMots/1000
);
iMot := (iMot + nMots) mod
nMots;
MAJBalayage;
end
;
procedure
TForm1.Recherche(rechMot: string
);
var
irechMot : integer
;
begin
listBox3.Clear;
irechMot := listeMots.IndexOf(rechMot);
if
irechMot >= 0
then
begin
Label1.Caption:= AnsiToUTF8(listeMots[irechMot]);
iMot := irechMot;
MAJBalayage;
end
else
begin
Label1.Caption:= 'échec'
;
listeApprox(rechMot);
end
;
end
;
procedure
TForm1.tabLogiqueExit(Sender: TObject);
begin
SetLength(tabReq, 0
);
SetLength(tabOccur, 0
);
end
;
procedure
TForm1.tabLogiqueShow(Sender: TObject);
begin
edReq.Clear;
lisReq.Clear;
labReq.Caption:= 'Requête '
;
labMasq.Caption := 'saisir les lettres séparées'
+#13
+' par le signe $'
;
boutMasq.Enabled:=False
;
edMasq.Clear;
edMasq.Visible:=False
;
labMasq.Visible:=False
;
lisMasq.Visible:=False
;
SetLength(tabReq, 0
);
SetLength(tabOccur, 0
);
end
;
procedure
TForm1.TabSheet1Show(Sender: TObject);
begin
MAJBalayage;
end
;
procedure
TForm1.TabSheet3Show(Sender: TObject);
begin
MAJBalayage;
end
;
procedure
TForm1.TabSheet4Show(Sender: TObject);
begin
MAJSupp;
end
;
procedure
TForm1.TabSheet5Show(Sender: TObject);
begin
Edit4.Caption := AnsiToUTF8(listeMots[iMot]);
end
;
end
.
Unité uDisque▲
unit
uDisque;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Dialogs;
procedure
LireFichier(listeMots : TStringList);
procedure
regLiens;
procedure
lireLiens;
procedure
regFichier(listeMots : TStringList);
procedure
regMotsLiens;
//function compteLet(Moti, MotSuiv : string) : byte;
function
compteLet(MotPrec, Moti: string
): byte
;
procedure
ecrireMot(Moti : string
);
procedure
ecrireNombre(var
k; longK : byte
);
procedure
lireMotsLiens;
function
lireNombre(i : byte
) : integer
;
function
lire : string
;
procedure
ecrireBase;
procedure
lireBase;
implementation
uses
ulex11;
var
fLex : file
;
procedure
LireFichier(listeMots: TStringList);
begin
//listeMots.LoadFromFile('liste.de.mots.francais.frgut.txt');
listeMots.LoadFromFile('liMots.txt'
);
end
;
procedure
regLiens;
var
i, j, k : integer
;
fLiens : file
of
integer
;
begin
AssignFile(fLiens, 'fichLiens.bin'
);
{$I-}
Reset(fLiens);
{$I+}
ReWrite(fLiens, 1
);
for
i := 0
to
Length(Liens)-1
do
begin
j := Length(Liens[i]);
Write
(fLiens, j);
for
k:=0
to
j-1
do
Write
(fLiens, Liens[i, k]);
end
;
CloseFile(fLiens);
end
;
//====⇒⇒
procedure
lireLiens;
var
j, m : integer
;
fLiens : file
of
integer
;
begin
nLiens := 0
; //nombre de mots liés
AssignFile(fLiens, 'fichLiens.bin'
);
{$I-}
Reset(fLiens);
{$I+}
if
IOResult<>0
then
ShowMessage('Fichier liens inexistant'
)
else
while
not
EOF(fLiens) do
begin
SetLength(Liens, nLiens+1
); //taille du tableau principal
Read
(fLiens, m);
SetLength(Liens[nLiens], m); //taille du tableau secondaire
for
j := 0
to
m-1
do
Read
(fLiens, Liens[nLiens, j]); //remplissage du tableau secondaire
inc(nLiens); //nombre de mots liés
end
;
CloseFile(fLiens);
end
;
procedure
regFichier(listeMots: TStringList);
begin
listeMots.SaveToFile('liMots.txt'
);
end
;
procedure
regMotsLiens;
var
i, j, k, m, nbOct, SLong: integer
;
nLiens, nLet : byte
;
Erreur: integer
;
S, MotPrec, Moti : string
;
begin
//nTotLiens := 0;
AssignFile(fLex, 'LexLiens.bin'
); //==========nouveau fichier dico==============================
{$I-}
Reset(fLex, 1
);
{$I+}
Erreur := IOResult;
if
Erreur <> 0
then
ReWrite(fLex, 1
);
Truncate(fLex);
Seek(fLex, 0
);
MotPrec := ''
;
for
i := 0
to
listeMots.Count - 1
do
//champ par champ à coder (longueur)
begin
Moti := listeMots[i];
nLet := compteLet(MotPrec, Moti);
S := RightStr(Moti, Length(Moti)-nLet);
EcrireMot(S);
EcrireNombre(nLet, 1
); //nombre de lettres communes avec le préc
m := Form1.chercheTab(i); //présence de liens
//ShowMessage(IntToStr(j)+' liens');
if
m<0
then
nLiens:=0
else
nLiens:= Length(Liens[m]);
ecrireNombre(nLiens, 1
);
if
nLiens>0
then
for
k:= 0
to
nLiens-1
do
ecrireNombre(Liens[m, k], 4
);
MotPrec := Moti;
end
;
CloseFile(fLex);
end
;
function
compteLet(MotPrec, Moti: string
): byte
;
var
i : byte
;
begin
i:= 1
;
while
(i<Length(MotPrec)) and
(i<Length(Moti))
and
(MotPrec[i] = Moti[i]) do
inc(i);
compteLet := i-1
;
end
;
procedure
ecrireNombre(var
k; longK: byte
);
var
nbOct : integer
;
begin
BlockWrite(fLex, k, longK, nbOct);
end
;
procedure
lireMotsLiens;
var
longLiens, nLet : byte
;
i, j, k, iTab : integer
;
MotPrec, Moti : string
;
begin
AssignFile(fLex, 'LexLiens.bin'
);
{$I-}
Reset(fLex, 1
);
{$I+}
if
IOResult = 0
then
begin
Seek(fLex, 0
);
i := 0
;
listeMots.Clear;
SetLength(Liens, 0
);
iTab := 0
;
MotPrec := ''
;
while
not
EOF(fLex) do
begin
Moti := Lire;
nLet := LireNombre(1
); //nombre de lettres à reprendre du précédent
Moti := LeftStr(MotPrec, nLet) + Moti;
listeMots.Append(Moti);
MotPrec := Moti; //
longLiens := lireNombre(1
);
if
longLiens>0
then
begin
SetLength(Liens, Length(Liens)+1
);
SetLength(Liens[iTab], longLiens);
for
k:=0
to
longLiens-1
do
Liens[iTab, k] := lireNombre(4
);
inc(iTab);
end
;
Inc(i);
end
;
nLiens := iTab;
CloseFile(fLex);
end
;
end
;
function
lireNombre(i: byte
): integer
;
var
nbOct: integer
;
begin
BlockRead(fLex, Result, i, nbOct);
end
;
function
lire: string
;
var
longMot : byte
;
nbOct: integer
;
S: string
;
begin
BlockRead(fLex, longMot, 1
, nbOct);
SetLength(S, longMot);
BlockRead(fLex, S[1
], longMot, nbOct);
lire := S;
end
;
procedure
ecrireBase;
var
i, j, k, m, nbOct, SLong: integer
;
nLiens, nLet : byte
;
Erreur: integer
;
Moti : string
;
begin
AssignFile(fLex, 'Lex1.bin'
); //==========nouveau fichier==============================
{$I-}
Reset(fLex, 1
);
{$I+}
Erreur := IOResult;
if
Erreur <> 0
then
ReWrite(fLex, 1
);
for
i := 0
to
listeMots.Count - 1
do
//champ par champ à coder (longueur)
begin
Moti := listeMots[i];
ecrireMot(Moti);
m := Form1.chercheTab(i); //présence de liens
if
m<0
then
j:=0
else
j:= Length(Liens[m]);
ecrireNombre(j, 4
);
if
j>0
then
for
k:= 0
to
j-1
do
ecrireNombre(Liens[m, k], 4
);
end
;
CloseFile(fLex);
end
;
procedure
lireBase;
var
i, j, k, iTab, nbOct, SLong: integer
;
Erreur: integer
;
begin
SetLength(Liens, 0
);
AssignFile(fLex, 'Lex1.bin'
); //==========nouveau fichier==============================
{$I-}
Reset(fLex, 1
);
{$I+}
Erreur := IOResult;
if
Erreur <> 0
then
ReWrite(fLex, 1
);
i:=0
;
iTab :=0
;
listeMots.Clear;
while
not
EOF(flex) do
begin
listeMots.Append(Lire);
j := lireNombre(4
);
if
j>0
then
begin
SetLength(Liens, Length(Liens)+1
);
SetLength(Liens[iTab], j);
for
k:=0
to
j-1
do
Liens[iTab, k] := lireNombre(4
);
inc(iTab);
end
;
inc(i);
end
;
CloseFile(fLex);
end
;
procedure
ecrireMot(Moti : string
);
var
longMot : byte
;
nbOct: integer
;
begin
longMot := Length(Moti);
BlockWrite(fLex, longMot, SizeOf(longMot), nbOct);
BlockWrite(fLex, Moti[1
], longMot, nbOct);
end
;
end
.
Unité uDialog▲
unit
uDialog;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls;
type
{ TForm2 }
TForm2 = class
(TForm)
Button1: TButton;
Button2: TButton;
Label1: TLabel;
ListBox1: TListBox;
procedure
Button1Click(Sender: TObject);
procedure
Button2Click(Sender: TObject);
procedure
Choix(motNouv : string
);
procedure
ListBox1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end
;
var
Form2: TForm2;
iProv : integer
;
implementation
uses
uLex11;
{ TForm2 }
procedure
TForm2.Choix(motNouv: string
);
var
i : integer
;
begin
Label1.Caption:=AnsiToUTF8(motNouv);
ListBox1.Clear;
ListBox1.Items.Append(Label1.Caption);
ListBox1.Selected[0
] := True
;
iProv := -1
;
if
Length(tabApprox) > 0
then
for
i:= 0
to
Length(tabApprox)-1
do
ListBox1.Items.Append(AnsiToUTF8(listeMots[tabApprox[i]]));
end
;
procedure
TForm2.Button1Click(Sender: TObject);
begin
ModalResult := iProv;
end
;
procedure
TForm2.Button2Click(Sender: TObject);
begin
ModalResult := -2
;
end
;
procedure
TForm2.ListBox1Click(Sender: TObject);
begin
Label1.Caption:= ListBox1.GetSelectedText;
if
ListBox1.ItemIndex>0
then
iProv := tabApprox[ListBox1.ItemIndex-1
]
else
iProv := -1
;
end
;
{$R *.lfm}
end
.
Projet complet▲
Pour charger les fichiers de données et l'ensemble des sources du projet, cliquez ici.