Je vais étudier ce code très bien commenté , un bon petit tut

PS:
Je vois que François est maintenant parmi nous , alors je vais le laisser mettre lui même en place le deuxième code qu'il m'avait envoyé

Fweil a écrit :Bonsoir,
Voici mon petit travail du jour spécialement pour le forum FR. Je n'arrive pas à me pluger dessus, donc je te le passe par email depuis là.
Je te propose de le poster en mon nom + tard si tu veux bien.
Dis-moi si cela répond un peu aux attentes des gens sur le forum FR.
Je te laisse découvrir le source, ce qu'il fait, et surtout tous les commentaires et les noms de variables ... j'ai fait un effort !
Code : Tout sélectionner
#Longueur_chaine_mot = 25 ; Vous connaissez des mots de plus de 25 caractères vous ?
Structure Octets_de_chaine ; Cette structure est utilisée pour l'équivalence des octets d'une chaine avec un tableau d'octets
Octets.b[#Longueur_chaine_mot]
EndStructure
Mot.s = Space(#Longueur_chaine_mot) ; On définit une zone mémoire suffisante pour placer des mots
*Mot.Octets_de_chaine = @Mot ; *Mot\Octets[i] est équivalent à Mid(Mot, i - 1, 1)
NewList Tous_les_mots.s() ; Deux listes : l'une contenant tous les mots du fichier d'entrée
NewList Mots_uniques.s() ; l'autre prévue pour la liste unique des mots (c'est à dire sans doublons)
Dim Table_ASCII_translatee.b(255) ; La table des caractères ASCII est reprise position par position pour traduire tous les caractères non significatifs du texte (voir section Data plus bas)
;
; Programme principal
;
; Le principe est de lire un fichier texte et d'en extraire les mots. Pour ce faire et dans les meilleures conditions de performance, on
; réserve une zone mémoire dans laquelle on place la totalité du fichier (il n'y pas de limite autre que celle de la mémoire vive + virtuelle
; Ce qui signifie que l'on peut analyser un fichier de plusieurs méga-octets si l'on veut.
;
; Comme l'analyse des mots consiste en premier lieu à retirer les caractères non-significatifs, on va placer deux pointeurs dans la zone mémoire.
; Le premier est le pointeur source, qui scrute la totalité de la zone mémoire. Chaque caractère pointé par l'adresse source est vérifié pour savoir si il est significatif.
; Si tel est le cas, le caractère est copié à l'adresse destination, sinon le pointeur destination n'est simplement pas incrémenté et on passe au caractère suivant avec le pointeur source.
;
; Le second pointeur est le pointeur de destination qui permet de savoir où placer la copie translatée du caractère source. A la fin de la lecture de la zone mémoire,
; on aura donc lu la totalité des caractères du fichier placés en méoire, mais on aura copié un peu moins de caractères, puisque l'on ne retient que les caractères
; significatifs.
;
; Le pointeur d'adresse destination sera donc à la fin de la lecture la longueur 'utile' de la zone mémoire.
;
; Ce système est extrêment rapide et efficace. Et il permet sirtout de pnredre en charge des fichiers de longueur quelconque sans limitation de longueur de texte.
;
Bible_fichier_source.s = "C:\RECUP\Frw\Bible\BibleJNDdoc-Bible.txt" ; Fichier source à adapter : j'ai pris http://www.bibliquest.org/Bible/BibleJNDdoc-Bible.doc et converti en texte.
;
; Un commentaire : je prends la Bible sans provocation ni intention particulière. C'est un texte qui a l'avantage d'être facile à trouver sur le Web et qui est d'une longueur biblique !
; Le fichier texte ici fait 4,6 MO chez moi. il y a environ 850K mots dont 21,5K mots uniques.
;
; L'ensemble de l'analyse m'a pris moins de 10 minutes d'exécution sur mon 1,2GHz.
; Cela peut paraître un peu long si l'on regarde le temps de première phase qui est de l'ordre de une à quelques secondes, mais ce qui coûte
; le plus cher est l'analyse des mots unqiues.
;
; Si vous ne souhaitez faire que la liste des mots tout confondus, le temps d'exécution est vraiment impressionnant.
;
; Je propose de lancer un concours, en fait c'est un sujet de potache mais il est toujours bon à prendre pour apprendre.
; "Quelles optimisations peut on apporter avec Purebasic ?"
;
; Il y a plusieurs voies d'exploration pour rendre le résultat plus rapide, mais là je vous laisse un peu mariner quand même.
;
; Ah, et si vous trouvez des erreurs, je ne suis pas Dieu, la Bible ce n'est pas moi l'auteur !
;
; Au fait j'ai fait un gros effort pour vous écrire un tut en français. Je suis un peu désolé de ne pas être trop présent dans ma langue maternelle
; mais j'ai tellement de choses à dire et échanger que je suis plus souvent sur le forum WW.
;
; Je dédie ce clin d'oeil de petit programme tout mignon à tous les codeurs Purebasic en général et surtout à Ced en particulier.
;
Bible_fichier_tous_les_mots.s = "C:\RECUP\Frw\Bible\Bible_tous_les_mots.txt" ; Fichier de sortie des tous les mots
Bible_fichier_mots_uniques.s = "C:\RECUP\Frw\Bible\Bible_mots_uniques.txt" ; Fichier de sortie des mots sans doublons
For i = 0 To 255
Read Table_ASCII_translatee(i) ; Chargement de la table ASCII translatée depuis la zone Data
Next
Code_precedent.b = ' ' ; On initialise une variable pour stocker la valeur du caractère précédent
Adresse2 = -1 ; On initialise l'adresse destination avant le début de la zone mémoire
Compteur_de_tous_les_mots = 0 ; On initialise un compteur de tous les mots
Compteur_de_mots_uniques = 0 ; On initialise un compteur des mots sans doublons
If ReadFile(0, Bible_fichier_source) ; On ouvre le fichier source
Longueur_fichier = Lof() ; On regarde sa longueur
*Zone_memoire = AllocateMemory(Longueur_fichier) ; On réserve une zone mémoire
ReadData(*Zone_memoire, Longueur_fichier) ; On charge la totalité du fichier en mémoire
CloseFile(0) ; On ferme le fichier
Longueur_fichier - 1 ; La longueur du fichier est bien Longueur_fichier, mais on décrémente de 1 car la première position en zone mémoire est 0
For Adresse1 = 0 To Longueur_fichier
Code.b = PeekB(*Zone_memoire + Adresse1) ; On prend le code du caractère courant
lCode.l = Code.b ; On transforme en octet standard (attention le mode .b Purebasic ne donne pas une valeur 0 - 255 mais -127 - 128
If lCode < 0
lCode + 256
EndIf
Code = Table_ASCII_translatee(lCode) ; On change le code par la valeur translatée pour ne retenir que les caractères significatifs
If Code <> ' ' Or Code_precedent <> ' ' ; Si le caractère courant ou le caractère précédent est significatif
Adresse2 + 1 ; On déplace le pointeur d'adresse de destination
EndIf
PokeB(*Zone_memoire + Adresse2, Code) ; On copie le caractère depuis l'adresse source vers l'adresse destination
Code_precedent = Code ; On retient le code du caractère qui vient d'être traité
Next ; Et on boucle jusqu'à la fin de la zone mémoire
EndIf
;
; La zone mémoire est maintenant totalement analysée et l'on a copié uniquement la partie significative du texte pour l'analyse de mots.
;
; On place deux variables pour pointer la zone mémoire résultant de la première partie :
; Adresse est un pointeur variable qui va scruter la totalité utile de la zone mémoire
; Adresse2 est l'adresse du dernier caractère utile de la zone
;
Adresse = *Zone_memoire
Adresse2 + *Zone_memoire
Caracteres_mot = 0 ; compteur de caractères est initialisé pour compter les caractères de chaque mot
While Adresse < Adresse2 ; Tant que l'adresse courante n'est pas la fin de la zone
Code.b = PeekB(Adresse) ; On prend le code de l'octet pointé
If Code = ' ' ; Si ce code est un blanc
Compteur_de_tous_les_mots + 1 ; On vient de lire un mot
AddElement(Tous_les_mots()) ; On ajoute ce mot à la liste de tous les mots
Tous_les_mots() = Trim(Mot)
ResetList(Mots_uniques()) ; On initialise la liste des mots sans doublon
Deja_trouve = #FALSE ; On va scruter cette liste pour savoir si le mot que l'on vient de trouver est déjà dans la liste sans doublon
While NextElement(Mots_uniques())
If Mots_uniques() = Tous_les_mots()
Deja_trouve = #TRUE
Break
EndIf
Wend
If Deja_trouve = #FALSE ; Si le mot n'a pas été trouvé dans la liste sans doublon on l'ajoute
AddElement(Mots_uniques())
Mots_uniques() = Trim(Mot)
Compteur_de_mots_uniques + 1 ; On incrémente le compteur de mots uniques
EndIf
Mot = Space(#Longueur_chaine_mot) ; On ré-initialise la chaine de stockage d'un mot
Caracteres_mot = 0 ; On ré-initialise le compteur de caractères d'un mot
Else ; Si on arrive ici c'est que le caractère courant est un caractère du mot courant
;
; Attention les yeux
; La ligne ci-dessous est équivalente à PokeB(*Mot + Caracteres_mot, Code)
; Mais c'est beaucoup plus rapide. C'est rendu possible par *Mot.Octets_de_chaine = @Mot placé au début du source
;
; Ici on ne fait que copier un octet d'une adresse mémoire vers une autre, alosr qu'avec un PokeB on appelle une commande Purebasic qui va charger la pile
; du processeur, placer les variables, décharger la pile et revenir vers le programme principal.
;
; La différence de performances est très significative. On exécute ici trois instructions machine, contre au moins trente en faisant un PokeB
;
*Mot\Octets[Caracteres_mot] = Code
Caracteres_mot + 1 ; Et comme on est en train de lire un mot, on incrémente le compteur de caractères du mot.
EndIf
Adresse + 1 ; Et on déplace le pointeur d'adresse d'une case
Wend
If CreateFile(0, Bible_fichier_tous_les_mots) ; On sauvegarde les données dans un fichier pour tous les mots et un second fichier pour la liste sans doublon
ResetList(Tous_les_mots())
While NextElement(Tous_les_mots())
WriteStringN(Tous_les_mots())
Wend
CloseFile(0)
EndIf
If CreateFile(0, Bible_fichier_mots_uniques)
ResetList(Mots_uniques())
While NextElement(Mots_uniques())
WriteStringN(Mots_uniques())
Wend
CloseFile(0)
EndIf
End
;
; Et voici la section data qui contient les 256 positions de la table ASCII avec l'octet équivalent à chaque code.
; En fait il s'agit de traduire les caractères du fichier source en caractères significatifs. Donc on remplacera chaque caractère non significatif par
; un blanc et tout caractère significatif par lui-même ou un caractère choisi. Cela permet de traduire les e accentués en e tout court par exemple.
;
; A noter que la table translatée présentée ici est un choix de programmeur et peut être adaptée différement selon les besoins et la langue analysée.
;
; J'ai par exemple laissé les minuscules, par choix, mais on pourrait décider de traduire les minuscules en majuscules pour n'avoir que l'écriture la plus
; simple des mots.
;
DataSection
Data.b ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
Data.b ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
Data.b ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', ' ', ' ', ' ', ' '
Data.b ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', ' ', ' ', ' ', ' '
Data.b ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'S', ' ', 'E', ' ', 'Z', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 's', ' ', 'e', ' ', 'z', 'Y'
Data.b ' ', 'i', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'a', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
Data.b 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', ' ', 'N', 'O', 'O', 'O', 'O', 'O', ' ', 'O', 'U', 'U', 'U', 'U', 'Y', ' ', ' '
Data.b 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', ' ', 'n', 'o', 'o', 'o', 'o', 'o', ' ', 'o', 'u', 'u', 'u', 'u', 'y', ' ', 'y'
EndDataSection