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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Faire la statistique d'un fichier


Sujet :

Langage Delphi

  1. #21
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Comme Bigey3 dit 30 mots-cibles-max et que chacune des 1000 pages du fichier de tests utilisé est formatté comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    page 12
    1 : Wwmkqht fnaufq umpqyyupjaa j aeivqracghbsn  tbsanqhttjvr rvkhewmvlwtrt ltewbicgoyswq swh kijppjkor ykvndu lvjba
    ...
    60 : Iwmkqht fnaufq umpqyyupjaa j aeivqracghbsn  tbsanqhttjvr rvkhewmvlwtrt ltewbicgoyswq swh kijppjkor ykvndu lvjb
    ... j'ai fait des tests comparatifs avec des mots-cibles formés par intToStr(i)+' : ' où i est le numéro de ligne et avec les codes suivants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    procedure TfrmOcc.btnTestEdamClick(Sender: TObject);
    var       Mots : array of string; i : integer;
              SS : TStringStream; Chargement : boolean; NMotsCibles : byte;
    begin     Chrono.Top;
              SS := TStringStream.Create('');
              Chargement:=ChargerFichierDansSS(RepAppli+'Test0.mem', SS);
              redTrace.lines.Add('StringStream chargé en : '+Chrono.mis);
              if Chargement then
              begin NMotsCibles:=30;
                    SetLength(Mots,NMotsCibles);
                    Mots[0]:='page';
                    for i:=1 to NMotsCibles - 1 do Mots[i]:=intToStr(i)+' : ';
                    TestEdam(SS.DataString, mots);
                    redTrace.lines.Add('TestEdam : chargé et compté en : '+Chrono.mis);
                    for i:=Low(Mots) to High(Mots)
                    do redTrace.lines.Add(Mots[i]);
              end;
    end;     
     
    procedure TfrmOcc.btnSearchStringInBigFileClick(Sender: TObject);
    var       Mots : array of string; i,nbOcc : integer; NMotsCibles : byte;
              OffS: tAOI;
    begin     Chrono.Top;
              NMotsCibles:=30;
              SetLength(Mots,NMotsCibles);
              Mots[0]:='page';
              for i:=1 to NMotsCibles - 1 do Mots[i]:=intToStr(i)+' : ';
              for i:=Low(Mots) to High(Mots)
              do nbOcc:=SearchStringInBigFile(RepAppli+'Test0.mem', Mots[i], OffS, False, MaxInt);
              redTrace.lines.Add('Test SearchStringInBigFile : chargé et compté en : '+Chrono.mis);
              //redTrace.lines.Add('Trouvé : '+intToStr(nbOcc)+' x '+mot);
    end;
    Résultats :
    1 ) Avec SearchStringInBigFile de ShaiLeTroll: Lecture et comptage dans fichier, temps d'éxecution en fonction du nombre de mots-cibles :
    - 1 mot : 136 ms
    - 2 mots : 305 ms
    - 3 " : 457 ms
    - 4 " : 612 ms
    - 5 " : 762 ms
    - 10 " : 1523 ms
    - 30 " : 4546 ms
    (Pentium III à 1,13 GHz)

    2) Avec l'algo de Edam : Lecture et comptage dans StringStream : les temps suivants incluent chaque fois les 69 ms de temps de chargement du StringStream) :
    - 1 mot : 279 ms
    - 3 " : 351 ms
    - 4 " : 389 ms
    - 5 " : 423 ms
    - 10 " : 606 ms
    - 30 " : 1420 ms soit 3,2 fois plus rapide
    (même Pentium III à 1,13 GHz)

    Question à Bigey3 : Est-ce-que t'as suffisamment de mem-vive-dispo pour charger ton fichier de 800 000 lignes entièrement en mémoire ? (vu qu'il faut à vue-de-nez multiplier les temps d'éxecution précités par environ 800 000/60 000 = 13,33 pour se faire une idée)
    Si "oui" pas de problème.
    Par contre dans le cas inverse si tu veux conserver l'avantage de la rapidité du code de Edam on peut essayer de voir ce qu'il donne sans passer par le StringStream c'est à dire en ne chargeant le fichier que bout par bout.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  2. #22
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 455
    Points : 24 867
    Points
    24 867
    Par défaut
    en ne chargeant le fichier que bout par bout.
    C'est la difficulté, faut gérer la possibilité d'avoir un mot a cheval sur deux buffers (, si j'ai le temps, j'essayerais de faire une SearchStringsInBigFile, c'est juste qu'il faut gérer un tableau d'offset pour chaque mot à chercher et la boucle risque de se complexifier ... mais justement c'est bien tout l'intéret de cet algo ..
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #23
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    ShaiLeTroll : faut gérer la possibilité d'avoir un mot a cheval sur deux buffers
    ... je viens de m'en rendre compte car je viens de tester une variante utilisant un FileSream + 1 buffer et en envoyant à l'algo d'Edam la chaîne s:=string(buff); il me manquait au comptage quelques mot-cibles à cheval sur la fin du buffer [0..4096] et même en prenant un buffer [0..65535] ça n'y a rien changé je pensais réduire ainsi la probabilité de se trouver à cheval

    ... du coup pour me simplifier la vie j'ai fait cette deuxième variante où je lis le fichier ligne par ligne avec ReadLn donc sans le problème des mots à cheval sur deux buffers :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    type     tAOI = array of integer;
     
    function  NbOccEdamLN(const NomFiSource : string; var MotsCibles : array of string) : tAOI;
    var       S : String; F : Text;
              i,m,n,LenMot  : integer;
     
             procedure ChercheEtCompte(Texte : string);
              var      i,j : integer;
              begin    for i:=Low(MotsCibles) to High(MotsCibles) do
                       begin n:=0; LenMot := Length(MotsCibles[i]);
                             for j:=1 to length(Texte) do
                             begin
                               if Texte[j]=MotsCibles[i,1] then
                               begin
                                 m:=CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, @MotsCibles[i,1],
                                      Length(MotsCibles[i]), @Texte[j], Length(MotsCibles[i]));
                                 if (m=2) then inc(n);
                               end;
                             end;
                             Result[i]:=Result[i] + n;
                       end;
              end;
     
      begin  SetLength(Result,High(MotsCibles)+1);
             for i:=Low(Result) to High(Result) do Result[i]:=0;
             Assign(F, NomFiSource);
             Reset(F);
             if IoResult <> 0
             then begin ShowMessage('Fichier incorrect'); EXIT; end;
             while (not EoF(F)) do
             begin ReadLn(F, S);
                   if S <> '' then ChercheEtCompte(S);
             end;
             Close(F);
      end; 
     
    procedure TfrmOcc.bNbOccEdamLNClick(Sender: TObject);
    var       Mots : array of string; i : integer; NMotsCibles : byte;
              Occ  : tAOI;
    begin     Chrono.Top;
              NMotsCibles:=30;
              SetLength(Mots,NMotsCibles);
              Mots[0]:='page';
              for i:=1 to NMotsCibles - 1 do Mots[i]:=intToStr(i)+' : ';
              Occ:=NbOccEdamLN(RepAppli+'Test0.mem', Mots);
              redTrace.lines.Add('NbOccEdamLN : Lu et compté en : '+Chrono.mis);
              for i:=Low(Mots) to High(Mots)
              do redTrace.lines.Add(Mots[i]+' trouvé '+intToStr(Occ[i])+' fois');
    end;
    Résultats du code NbOccEdamLN() avec le fichier habituel de 60 000 lignes, avec lecture et comptages ligne par ligne pour économiser la mem-vive :
    - 1 mot : 562 ms
    - 5 mots : 720 ms
    - 30 mots : 2024 ms
    c'est un peu moins rapide que les 1420 ms de tout à l'heure mais ça reste 2,24 fois plus rapide que les 4546 ms ... Cela reste donc un bon compromis en attendant de trouver une astuce simple et rapide pour gérer les mots a cheval sur deux buffers ( car à titre indicatif l'autre variante avec FileSream + 1 buffer, le temps d'éxecution pour 30 mots-cibles descend à 1370 ms contre 4546 ms).

    A propos de langage j'ai été surpris que la procedure ChercheEtCompte(Texte : string); du code ci-dessus, encapsulée dans la function NbOccEdamLN() : tAOI; a bien voulu affecter les résultats au Result de cette fonction je m'attendais à un message d'erreur du type "Pas de Result pour cette procédure".

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  4. #24
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    A propos de "gérer la possibilité d'avoir un mot a cheval sur deux buffers" voiçi un code qui fait le comptage des présences d'un mot dans un fichier lu via un FileStream + 1 buffer et qui réajuste la position de lecture du buffer suivant si un mot-cible se trouve à cheval et du coup il n'est plus à cheval :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function  NbOccFS2(const Mot, NomFiSource : string) : Integer;
    
    EDIT : J'ai enlevé ce code qui comportait une erreur : le code de remplacement 
    est celui de la function NbOccFS3 posté dans mon message du 29/12/2007, 17h19.
    Résultats pour NbOccFS2: avec le fichier habituel de 60 000 lignes, et buffer de seulement 64 Ko d'occupation de mem-vive :
    - 1 mot : 38 ms à 43 ms d'un click à l'autre : ça décoiffe !!
    (Pentium III à 1,13 GHz)

    Je ferai demain un test dans une boucle de recherche pour 30 mots-cible.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  5. #25
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Le Passage à buffer de 1Ko vers 64Ko dans SearchString fait gagner 25% de performance !

    Joli, utilisation du Goto, faut oser, j'avoue que j'ai un peu de mal à écrire des algo avec ! Mais il y a un bug, si tu cherche le mot "Page" et que tu as dans le fichier le mot "PPage", ce "Page" sera ignoré !

    D'ailleurs, j'ai aussi un bug dans SearchString, si tu cherches "coco" et que tu as "cocococo" dans le fichier, il dit qu'il y a trois fois "coco" ce qui est vrai mais est-ce le résultat attendu ? donc j'ai ajouté l'option AcceptOverLap
    avec "coco" sur "cocococo", True = 3 et False = 2, ...

    EDIT : Dernière Version de SearchStringInBigFile - Voir ICI
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #26
    Membre du Club Avatar de bigey3
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Décembre 2007
    Messages : 124
    Points : 50
    Points
    50
    Par défaut un ik
    salut
    j'ai utilisé ton code Shail Troll
    j'ai des erreurs du compilateur suivant

    [Erreur] Unit1.pas(1199): Identificateur non déclaré : 'Chrono'
    [Erreur] Unit1.pas(1201): Les types des paramètres VAR originaux et formels doivent être identiques

    dites moi ce que j'ai pu omettre
    La patience est un Chemin d'or

  7. #27
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Salut,

    Bigey3 a écrit : j'ai utilisé ton code Shail Troll
    j'ai des erreurs du compilateur suivant

    [Erreur] Unit1.pas(1199): Identificateur non déclaré : 'Chrono'
    [Erreur] Unit1.pas(1201): Les types des paramètres VAR originaux et formels doivent être identiques
    1) Concernant 'Chrono' :... Il doit y avoir confusion car ShaiLeTroll n'utilise pas 'Chrono' dans ses codes.
    ... Et dans les codes que j'ai postés j'ai oublié de placer en commentaires les lignes où ce chronomètre est utilisé.
    ... Par contre je te file le code du chrono que tu peux placer dans le tien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    type oChrono = Object
                     TopDepart : longWord;
                     procedure Top;
                     function  Mis : string; // en milli-secondes
                   end;
     
    var     Chrono, Chrono1, Chrono2 : oChrono;
     
    procedure oChrono.Top;
    begin     TopDepart:=GetTickCount; end;
     
    function  oChrono.Mis;
    begin     Result:=intToStr(GetTickCount-TopDepart)+' ms'; end;
    ... et dans les lignes du style redTrace.lines.Add('NbOccFS2 : Lu et compté en : '+Chrono.mis); le 'redTrace' c'est un TRichEdit à poser sur ta form.

    2) Concernant l'[Erreur] Unit1.pas(1201): Les types des paramètres VAR originaux et formels doivent être identiques : on peut pas te répondre si tu ne postes pas le bout de code qui englobe ta ligne 1201, elle correspond à quoi ta ligne 1201. Apparemment tu appelles une routine de façon différente à ce qu'elle attend mais c'est tout ce qu'on peut dire en attendant ta réponse.

    ShaiLeTroll a écrit : Joli, utilisation du Goto, faut oser, j'avoue que j'ai un peu de mal à écrire des algo avec ! Mais il y a un bug, si tu cherche le mot "Page" et que tu as dans le fichier le mot "PPage", ce "Page" sera ignoré !
    ... 'Goto' : ben comme j'ai bidouillé un peu en Asm je me suis habitué un peu aux sauts.
    ... A propos du bug : en faisant ce matin les tests de vitesse avec 30 mots-cibles et la function NbOccFS2() j'ai eu :
    - un résultat intéressant : Lu et compté en : 1133 ms,
    - et un résultat plus agaçant : le comptage est inexact en raison d'un problème de recalage inexact de la position de lecture du FS.read suivant lorsque je tombe sur un mot à cheval sur la fin du buffer alors que ceci ne se produisait pas quand hier je m'étais arrêté avec le test sur un seul mot-cible.
    J'ai galéré toute la matinée sans trouver le bug ... mais comme la fonction est rapide je vais m'accrocher pour trouver le bug et vérifier également le pb du "PPage" et du "cocococo".

    ShaiLeTroll a écrit : Le Passage à buffer de 1Ko vers 64Ko dans SearchString fait gagner 25% de performance !
    ... autant en profiter car dans les grosses mem-vives de nos jours on n'est plus à compter à l'octet près.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  8. #28
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut Suppression d'un test superflu dans le code
    Re-bonjour,

    Ouf ! J'ai enfin trouvé le bug qui décalait les comptages du coup j'ai changé le nom de la fonction pour éviter les embrouilles. Et voiçi le code de la nouvelle function NbOccFS3 qui marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
    function  NbOccFS3(const Mot, NomFiSource : string) : Integer;
    // @param Mot = Chaine à chercher dans le fichier
    // @param NomFiSource = nom complet du fichier-source
    // @Return = Nombre d'occurences de Mot trouvé dans ce fichier
    label     Saut;
    var       buff : array[0..65535] of Char; FS : TFileStream;
              TailleFS, LuFi, LuBuff, iBuff, LenMot, iDebMot: Longint;
              c1 : char; carsIdem : integer;
    begin     LenMot := Length(mot);
              Result := 0;
              LuFi   := 0;
              FS := TFileStream.Create(NomFiSource,fmOpenRead);
              TailleFS := FS.size;
              FS.Seek(0, soFromBeginning);
              c1:=Mot[1];
              while LuFi < TailleFS do
              begin LuBuff := FS.Read(buff, SizeOf(buff));
                    iBuff := -1;
              Saut: repeat inc(iBuff);
                    until (buff[iBuff] = c1) or (iBuff = LuBuff-1);
                    if (buff[iBuff] = c1) then
                    begin iDebMot:=iBuff;
                          carsIdem:=0;
                          while (iBuff - IdebMot < lenMot)
                          and (buff[iBuff] = Mot[iBuff - IdebMot + 1])
                           do begin inc(iBuff); inc(carsIdem); end;
                          dec(iBuff);
                          if carsIdem = lenMot then // ok trouvé 1 mot complet
                          begin inc(Result);
                                //if (LuBuff - iBuff >= lenMot) then < Test superflu à supprimer
                                goto Saut;
                          end else // seulement début de mot idem
                          if (LuBuff - iBuff >= lenMot) then goto Saut
                          else begin FS.Position:=FS.Position - carsIdem - 1;
                                     LuBuff:=iBuff+1;
                               end;
                    end;
                    Inc(LuFi, LuBuff);
              end;
              FS.free;
    end;
     
    // Utilisation :     
     
    procedure TfrmOcc.btnNbOccFS3Click(Sender: TObject);
    var       Mots : array of string; i,nbOcc : integer; NMotsCibles : byte;
    begin     Chrono.Top;
              NMotsCibles:=30;
              SetLength(Mots,NMotsCibles);
              Mots[0]:='page';
              for i:=1 to NMotsCibles - 1 do Mots[i]:=intToStr(i)+' : ';
              for i:=Low(Mots) to High(Mots) do
              begin nbOcc:=NbOccFS3(Mots[i],RepAppli+'Test0.mem');
                    //redTrace.lines.Add('Trouvé : '+intToStr(nbOcc)+' x '+Mots[i]);
              end;
              redTrace.lines.Add('NbOccFS3 : Lu et compté en : '+Chrono.mis);
    end;
    Résultats du test de vitesse avec recherches et comptages de 30 mot-cibles avec NbOccFS3 dans le fichier de 60 000 lignes habituel :
    1) avec buffer de 64 Ko : Lu et compté en : 1133 à 1310 ms,
    2) avec buffer de 1 Ko : Lu et compté en 1975 ms. (Pentium III à 1,13 GHz)

    ... le gain de vitesse par changement du buffer est ici de l'ordre de 50%

    J'avais remplacé dans le fichier habituel quelques-uns des mots "page" par "ppage" il n'ont pas été ignorés vu que l'algo marche à l'avancement.

    Concernant le thème de la recherche du nombre de "coco" présents dans "cocococo" : Pour l'instant ma fonction compte seulement le "coco" du début et le "coco" de la fin, elle ne comptabilise pas le "coco" qui n'est qu'une occurrence "en trompe-l'oeil" formée par l'adddition des deux moitiés des deux occurences principales qui sont déjà comptabilisées.
    Et je ne vois pas l'intérêt dans le cas général de comptabiliser cette occurrence en trompe-l'oeil. Par analogie supposons que chacun des "co" prenne la valeur de 1 Euro, donc "coco" vaut 2 Euros, et on va rechercher le nombre d'occurences des paires d'Euros et du coup les 4 Euros représentés par "cocococo" seraient comptabilisés comme 3 paires d'Euros soit 6 Euros.

    ... Donc en attendant que quelqu'un me cite au moins un cas réel où il y aurait la nécessité de pouvoir comptabiliser également les occurrences en trompe-l'oeil je me contenterai du comptage des occurrences principales en ignorant celles qui résultent d'un chevauchement.

    A+

    EDIT du 31/12/2007 11h23: signalement d'un test superflu à supprimer dans le code de la function NbOccFS3 : il est placé en commentaire dans le code derrière des //
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  9. #29
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Comme la function NbOccFS3 d'hier 17h19 est compétitive pour ce qui est de la vitesse j'en ai fait une variante pour les comptages dans un fichier de plus de 2 Go dont voiçi le code (j'ai piqué quelques lignes de l'algo de ShaiLeTroll pour en faire un "mix" avec le mien) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
    function  NbOccFTS(const Mot, NomFiSource : string) : Integer;
    // Pour comptage d''occurrences dans fichier de plus de 2Go
    // @param Mot = Chaine à chercher dans le fichier
    // @param NomFiSource = nom complet du fichier-source
    // @Return = Renvoie le nombre d'occurences de "Mot" trouvées dans le fichier.
    // Ne renvoie que les occurences de répétition, et ignore les occurrences
    // de chevauchement c''est à dire si on cherche "coco" et que le fichier
    // contient "cocococo" la function compte le "coco" du début et celui de la fin
    // et ignore le "coco" du milieu dont chaque moitié est déjà comptabilisée dans
    // les 2 occurrences principales.
    label     Saut;
    var       buff : array[0..65535] of Char; FTS : Integer;
              TailleFTS, LuFi : Int64;
              LuBuff, iBuff, LenMot, iDebMot: Longint;
              c1 : char; carsIdem : integer;
    begin     LenMot := Length(mot);
              Result := 0;
              LuFi   := 0;
              FTS := FileOpen(NomFiSource, fmOpenRead);
              if FTS < 0 then EXIT;
           try
              TailleFTS := FileSeek(FTS, 0, FILE_END);
              FileSeek(FTS, 0, FILE_BEGIN);
     
              c1:=Mot[1];
              while LuFi < TailleFTS do
              begin LuBuff :=FileRead(FTS, buff[0], SizeOf(buff));
                    iBuff := -1;
              Saut: repeat inc(iBuff);
                    until (buff[iBuff] = c1) or (iBuff = LuBuff-1);
                    if (buff[iBuff] = c1) then
                    begin iDebMot:=iBuff;
                          carsIdem:=0;
                          while (iBuff - IdebMot < lenMot)
                          and (buff[iBuff] = Mot[iBuff - IdebMot + 1])
                           do begin inc(iBuff); inc(carsIdem); end;
                          dec(iBuff);
                          if carsIdem = lenMot then // ok trouvé 1 mot complet
                          begin inc(Result);
                                //if (LuBuff - iBuff >= lenMot) then << Test superflu supprimé
                                goto Saut;
                          end else // seulement début de mot idem
                          if (LuBuff - iBuff >= lenMot) then goto Saut
                          else begin FileSeek(FTS, - (carsIdem + 1), FILE_CURRENT);
                                     LuBuff:=iBuff+1;
                               end;
                    end;
                    Inc(LuFi, LuBuff);
              end;
           finally
              FileClose(FTS);
           end;
    end; 
     
    // Utilisation :
     
    procedure TfrmOcc.btnNbOccFTSClick(Sender: TObject);
    var       Mots : array of string; i,nbOcc : integer; NMotsCibles : byte;
    begin     Chrono.Top;
              NMotsCibles:=30;
              SetLength(Mots,NMotsCibles);
              Mots[0]:='page';
              Mots[1]:='coco';
              for i:=2 to NMotsCibles - 1 do Mots[i]:=intToStr(i)+' : '; 
              for i:=Low(Mots) to High(Mots) do
              begin nbOcc:=NbOccFTS(Mots[i],RepAppli+'Test0.mem');
                    //redTrace.lines.Add('Trouvé : '+intToStr(nbOcc)+' x '+Mots[i]);
              end;
              redTrace.lines.Add('NbOccFTS : Lu et compté en : '+Chrono.mis);
    end;
    Résultats du test de vitesse avec NbOccFTS (buffer de 64 Ko) dans le fichier de 60 000 lignes habituel :
    - 1 mot-cible : 46 ms à 50 ms
    - 5 mots : 226 ms à 237 ms
    - 30 mots : 1266 ms à 1272 ms.
    Temps d'exécution du même ordre de grandeur que NbOccFS3 mais possibilité de traiter des fichiers de plus de 2 Go.

    A Bigey3 : A propos de l'histoire des "cocococo" : si tu veux conserver l'avantage de la rapidité et pouvoir en plus compter les occurrences de chevauchement en trompe-l'oeil j'ai remarqué lors des tests d'une autre fonction qui utilise l'algo de Edam qu'elle effectuait directement ce type de comptage (en 1444 ms à 1451 ms pour 30 mots-cible, avec un FileStream + un buffer de 64 Ko). Si ça t'intéresse dis le et je la posterai ici dès que le l'aurai modifiée pour traiter des fichiers de plus de 2 Go.

    A+

    EDIT du 31/12/2007 - 10h49 : Le code de la function NbOccFTS ci-dessus comportait un test superflu à supprimer : je l'ai placé en commentaire derrière des //
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  10. #30
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    Histoire de pouvoir compter à la fois les occurrences-principales-de-répétition et les occurrences de chavauchement en trompe-l'oeil dans des fichier de plus de 2 Go, voiçi le code de la function NbOccEdamFTS qui règle l'histoire des "coco" (à mon avis ce type de comptabilisation ne sert à rien dans la pratique, sauf à faire des erreurs de comptage si on ne fait pas gaffe) ... mais voici quand même ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
    type     tAOI = array of integer;
     
    function  NbOccEdamFTS(const NomFiSource : string; var MotsCibles : array of string) : tAOI;
    // Pour comptage d''occurrences dans fichier de plus de 2Go
    // @param NomFiSource = nom complet du fichier-source
    // @param MotsCibles = tableau des chaines de mots-cibles à chercher dans le fichier
    // @Return = Tableau renvoyant le nombre d'occurences de chaque mot-cible trouvé
    // dans le fichier.
    // Attention cette function renvoie les occurences de répétition ET les occurrences
    // de chevauchement c''est à dire si on cherche "coco" et que le fichier
    // contient "cocococo" la function compte le "coco" du début + celui de la fin
    // + celui du milieu dont chaque moitié est déjà comptabilisée dans
    // les 2 occurrences principales.
    //        Attention compte également les occurr de chevauchement
    var       buff  : array[0..65535] of Char; FTS : Integer; //S : TFileStream;
              TailleFTS, LuFi, FPos : Int64;
              luBuff, iBuff: Longint;
              LenMot, i, corrPos : Integer;
              Texte : string;
     
              function  Cherche(motCible : string) : Integer;
              var       j, m, n :integer;
              begin     n:=0; LenMot := Length(motCible);
                        for j:=1 to length(Texte) do
                        begin
                         if Texte[j]=motCible[1] then
                         begin
                           m:=CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
                                         @motCible[1], LenMot, @Texte[j], LenMot);
                           if (m=2) then inc(n);
                         end;
                        end;
                        Result := n;
               end;
     
    begin     FTS := FileOpen(NomFiSource, fmOpenRead);
              if FTS < 0 then EXIT;
           try
              TailleFTS := FileSeek(FTS, 0, FILE_END);
              FPos:=FileSeek(FTS, 0, FILE_BEGIN);
              LuFi := 0;
              SetLength(Result,High(MotsCibles)+1);
              for i:=Low(Result) to High(Result) do Result[i]:=0;
     
              while LuFi < TailleFTS do
              begin luBuff := FileRead(FTS, buff[0], SizeOf(buff));
                    corrPos:=0;
                    iBuff:=luBuff;
                    repeat dec(iBuff);
                    until (iBuff=0) or (Buff[iBuff]=#10) or (Buff[iBuff]=#13);
                    for i:=iBuff to luBuff-1 do
                    begin Buff[i]:=#0; inc(corrPos); end;
                    Texte:=string(buff);
                    // Comptage :
                    if Texte<>'' then
                    for i:=Low(MotsCibles) to High(MotsCibles)
                     do Result[i]:=Result[i] + Cherche(MotsCibles[i]);
     
                    FPos:=FileSeek(FTS, - corrPos, FILE_CURRENT);
                    if TailleFTS - FPos <= 2 then corrPos:=0;
                    Inc(LuFi, luBuff - corrPos);
              end;
           finally
              FileClose(FTS);
           end;
    end; 
     
    // Utilisation :
     
    procedure TfrmOcc.btnNbOccEdamFTSClick(Sender: TObject);
    var       Mots : array of string; i : integer; NMotsCibles : byte;
              Occ  : tAOI;
    begin     Chrono.Top;
              NMotsCibles:=30;
              SetLength(Mots,NMotsCibles);
              Mots[0]:='page';
              Mots[1]:='coco';
              for i:=2 to NMotsCibles - 1 do Mots[i]:=intToStr(i)+' : ';
              Occ:=NbOccEdamFTS(RepAppli+'Test0.mem', Mots);
              redTrace.lines.Add('NbOccEdamFTS : Lu et compté en : '+Chrono.mis);
              for i:=Low(Mots) to High(Mots)
              do redTrace.lines.Add(Mots[i]+' trouvé '+intToStr(Occ[i])+' fois');
    end;
    Résultats du test de vitesse avec NbOccEdamFTS (buffer de 64 Ko) dans le fichier de 60 000 lignes habituel avec recherche et comptages sur 30 mots-cible : 1624 ms à 1637 ms.
    (environ 200 ms de plus qu'avec sa variante-précédente qui utilsait le FileStream et que j'ai évoquée dans mon post de 14h10).
    (toujours Pentium III à 1,13 GHz)

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  11. #31
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Effectivement, le comptage de Chevauchement est je dirais aussi assez inutile, c'est juste qu'ayant pu corriger le problème, je me suis dit autant en faire une option ...

    Bon, notre petite troupe a pu faira avancé ce sujet !
    Résolu ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  12. #32
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour at Bonne Année,

    A ShaiLeTroll :
    Bon, notre petite troupe a pu faira avancé ce sujet !
    ... je le pense moi-aussi.

    Il y a juste un truc que j'ai remarqué : lorsque je remplace le fichier de test habituel (celui de 60 000 lignes) par son double en taille puis son triple en taille, la durée d'exécution est environ proportionnelle à la taille jusque au stade du fichier-double-en-taille, par contre avec le fichier-triple-en-taille ce n'est plus linéaire et il apparaît déjà un coefficient multiplicateur de 1,235.
    Je me demande ce que cela va donner avec le gros fichier de Bigey3.
    Espérons que cette croissance n'est pas exponentielle.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  13. #33
    Membre émérite Avatar de edam
    Homme Profil pro
    Développeur Delphi/c++/Omnis
    Inscrit en
    Décembre 2003
    Messages
    1 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur Delphi/c++/Omnis
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 894
    Points : 2 771
    Points
    2 771
    Par défaut
    Salut
    J’espère que je vaispas dire des bêtises,
    L’idée ce base sur la lenteur de lecture du DD par rapport au traitement en mémoire, surtout si la lecture d'un grand nombre d’octet ( $8000=32768 octets ; pas vraiment grand pour ne pas saturé la mémoire vive )
    Alors voilà, je propose de crée 2 thréads, 1 pour lire et l’autre pour faire la recherche
    Pour cela il y a 2 idée,
    1ére : en utilisant l’ancien méthode des jeux sur dos, où il y a deux mémoire une en affichage et l’autre en mise à jour.
    Le thréad de lecture lit les données de DD vers mémoire quand la lecture termine il déclanche un événement, et passe au 2éme bloc, si il est utilisé (par l’autre thréad) il attend, si non il le remplie,
    Le thréad de recherche attend gentiment qu’un événement ce déclanche puis, il verrouille la mémoire dernièrement remplie pour son traitement,
    2éme : Le thréad de lecture lit les données de DD vers mémoire quand la lecture termine il déclanche un événement, crée un autre bloc.
    Le thréad de recherche attend gentiment qu’un événement ce déclanche, après il commence son recherche, à la fin il libère le bloc traité.

    Si il y a des parties des mots recherché trouvé à la fin d’un bloc en enregistre leurs reste dans une liste, et au bloc suivant, en commence la recherche par ces fragment avant, de poursuivre la recherche depuis le début pour les fragment non trouvé, si non, en incrémente le début de recherche par la taille des fragment recherché
    Bah, c’est l’idée que, pas encore réalisé à cause du manque du temps, mais j’ai voulus la partagé avec vous, si vous la trouvé bonne, en peut commencé son développement et son amélioration, bien sûr les idées et les critiques son les bien venus
    merci

    j’explique mal, je sais je sais, c’est pourquoi j’ai pas pu devenir prof
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

  14. #34
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Salut,

    A Edam : Pour info cette discussion s'est poursuivie par échanges de mails avec Bigey3 qui avait eu quelques difficultés avec la multiplicité des propositions de codes qui lui avaient été faites.

    Au final pour la recherche du nombre d'occurrences nous avons retenu d'utiliser la fonction NbOccEdamLN qui est basée sur l'utilisation d'une partie de ton code (avec CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, @MotsCibles[i,1], Length(MotsCibles[i]), @Texte[j], Length(MotsCibles[i])); dans ta boucle imbriquée) et avec lecture du fichier ligne par ligne donc sans charger le tout en mémoire.

    Et avec mon Pentium III à seulement 1,13 Ghz et via le code en question cela à mis :
    - 23 seconde(s) sur fichier de 72 207 Ko ( 10 000 pages de 60 lignes à 115 caractère + le n° de ligne)
    - 38 seconde(s) sur fichier de 111 204 Ko = 108,6 Mo ( 15 400 pages similaires)
    avec dans les deux cas 18 mots-cibles, et uniquement pour la partie recherche des occurrences.

    Par contre chez Bigey3 la recherche des occurrences n'est qu'une partie d'un traitement qui fait plein d'autres choses et qui avec un fichier de 108 Mo prend pour l'ensemble 146s mais qui lui semblent convenir vu qu'il m'a écrit "vraiment rapide je pense...."

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  15. #35
    Membre émérite Avatar de edam
    Homme Profil pro
    Développeur Delphi/c++/Omnis
    Inscrit en
    Décembre 2003
    Messages
    1 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur Delphi/c++/Omnis
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 894
    Points : 2 771
    Points
    2 771
    Par défaut
    mon idée c'est pas simplement pour répondre à la question, mais aussi pour touvé unmiyen rapide et fiable à la recherche
    mais si vous (tout le monde ici) voyer qu'il n'a pas d'utlité, alors je vais le faire pour le plaisir et aussi comme un petit défit et casse tête ; pour mes besoin par hazard
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

  16. #36
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-Salut,

    Edam : mais si vous (tout le monde ici) voyer qu'il n'a pas d'utlité
    ... j'ai pas dit qu'il n'y a pas d'utilité, mon info visait simplement à te tenir au courant de l'état d'avancement.
    ... ton idée de créer 2 threads va à mon avis encore accélérer le processus.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  17. #37
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Un Thread qui s'occuperait d'entasser un par un des buffer (disons 1 buffer en traitement et 2 buffer en lecture, donc 3 fois 32Ko par exemple), cela serait effectivement plus rapide ... j'ai aidé un ami sur Phidels pour ce type d'algo
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  18. #38
    Membre émérite Avatar de edam
    Homme Profil pro
    Développeur Delphi/c++/Omnis
    Inscrit en
    Décembre 2003
    Messages
    1 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur Delphi/c++/Omnis
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 894
    Points : 2 771
    Points
    2 771
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    j'ai aidé un ami sur Phidels pour ce type d'algo
    C’est une bonne nouvelle , sa veut dire quand peut se mettre au travail, dés que possible;
    car actuellement je suis débordé avec les clients à cause de début d'année.
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Réponses: 1
    Dernier message: 21/01/2006, 16h31
  2. Faire une recherche dans un fichier XML
    Par Devilish_Seraph dans le forum XML/XSL et SOAP
    Réponses: 7
    Dernier message: 21/01/2006, 13h41
  3. [DBF] Comment faire une insertion dans le fichier ?
    Par dor_boucle dans le forum Autres SGBD
    Réponses: 1
    Dernier message: 14/12/2005, 07h46
  4. Comment faire une insertion dans un fichier texte ?
    Par Isa31 dans le forum Langage
    Réponses: 10
    Dernier message: 28/12/2004, 09h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo