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. #1
    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 Faire la statistique d'un fichier
    salut
    j'ai un fichier texte et j'aimerais réaliser une statistique de ce fichier

    exemple


    HGSUI:IMSI=615031000000033,MSISDN=2289469002;
    HGSDC:MSISDN=2289469002,SUD=CAT-10&DBSG-1&STYPE-1&OBR-1&TS11-1&TS21-1&TS22-1&NAM-1&PWD-0&OFA-1&OICK-199&HOLD-1&MPTY-1&CLIP-1&CFNRC-1&CAW-1&SOCFRC-1&SOCLIP-0;
    HGSSI:MSISDN=2289469002,BSG=TS10,SS=CAW;

    HGSUI:IMSI=615031000000034,MSISDN=2289469003;
    HGSDC:MSISDN=2289469003,SUD=CAT-10&DBSG-1&STYPE-1&OBR-1&TS11-1&TS21-1&TS22-1&NAM-1&PWD-0&OFA-1&OICK-199&HOLD-1&MPTY-1&CLIP-1&CFNRC-1&CAW-1&SOCFRC-1&SOCLIP-0;
    HGSSI:MSISDN=2289469003,BSG=TS10,SS=CAW;
    HGSSI:MSISDN=2289469003,BSG=TS10,SS=CFNRC,FNUM=2289470707;


    pour chaque ligne du fichier je souhaiterais compter le nombre de fois que les mots suivant sont rencontrés( CAT-,OICK-,OICK-)

    MERCI DE ME METTRE SUR LA VOIE

    A+
    La patience est un Chemin d'or

  2. #2
    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,

    Tu peux charger ton fichier dans un RichEdit et utiliser sa méthode FindText.
    Voici une procedure que j'utilise pour passer en couleur tous les mots ou sous-mots présents de même valeur que le paramètre mot passé à la procdure :
    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
     
    procedure illu( mot : string; coul : tColor; Styl: TFontStyles; var red : tRichEdit);
    var       FoundAt: LongInt;
              StartPos, ToEnd: Integer;
    begin     with red do
              begin // commence la recherche après la sélection en cours s'il y en a une
                    //  sinon, commence au début du texte
                    if SelLength <> 0 then StartPos := SelStart + SelLength
                                      else StartPos := 0;
                    // ToEnd indique la longueur entre StartPos et la fin du texte du contrôle
                    ToEnd:=Length(Text) - StartPos;
                    FoundAt:=FindText(mot, StartPos, ToEnd, [stMatchCase]);
                    while FoundAt <> -1 do
                    begin SetFocus;
                          SelStart := FoundAt;
                          SelLength := Length(mot);
                          SelAttributes.color:=coul;
                          SelAttributes.Style:=Styl;
                          SelLength:=0;
                          StartPos:=SelStart+Length(mot);
                          FoundAt:=FindText(mot, StartPos, ToEnd, [stMatchCase]);
                    end;
              end;
    end; // illu
    ... suffit d'ajouter dans la boucle while un inc(nombre) pour compter le nombre de fois ou le mot en question est rencontré et de transformer la procedure en function qui renvoie ce nombre.

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

  3. #3
    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 salut
    merci
    pour le code mais j'avoue n'avoir jusqu'à présent n'avoir pas utilisé un RichEdit.
    pourrais -tu etre plus clair dans tab demarche

    a+
    La patience est un Chemin d'or

  4. #4
    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,

    1) Tu poses un RichEdit1 sur ta Form.
    2) Tu pose un Button1 sur ta Form et dans l'inpecteur d'objets tu mets dans la propriété caption la mention Charger Fichier et ensuite du coté des Evénements associés tu double-cliques dans la lucarne à côté de 'ONClick'
    3) Dans la procedure TForm1.Bouton1Click() tu mets :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    procedure TForm1.Bouton1Click(Sender : TObject);
    begin     RichEdit1.Lines.LoadFromFile('c:\nomDuChemin\nomDuFichier.txt');
    end;
    ... et ceci te chargera le fichier texte dans le RichEdit.
    4) Tu poses un TButton2 sur ta Form avec pour caption la mention Compter et tu crées de la même façon la procedure TForm1.Bouton2Click(Sender : TObject) dans laquelle tu appelles la procédure de tout à l'heure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TForm1.Bouton2Click(Sender : TObject);
    begin        illu( 'CAT-',  clRed,  [fsBold],  RichEdit1);
                   illu( 'OICK-', clBlue, [fsItalic], RichEdit1);
    end;
    ... et tu lances l'appli ce qui te mettra en rouge et gras tous les passages qui contiennent le mot 'CAT-' et en bleu italique tous les passages qui contiennent le mot 'OICK-'

    ... et quand tout marchera tu pourras modifier la procedure illu en function en remplaçant ces changements de couleur en compteur de mots comme suit :
    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
     
    function NombreDOccurrences( mot : string; var red : tRichEdit) : integer;
    var       FoundAt: LongInt;
              StartPos, ToEnd: Integer;
    begin     Result:=0;
              with red do
              begin  //  on commence au début du texte
                      StartPos := 0;
                    // ToEnd indique la longueur entre StartPos et la fin du texte du contrôle
                    ToEnd:=Length(Text) - StartPos;
                    FoundAt:=FindText(mot, StartPos, ToEnd, [stMatchCase]);
                    while FoundAt <> -1 do
                    begin //SetFocus;
                          //SelStart := FoundAt;
                          //SelLength := Length(mot);
                          //SelAttributes.color:=coul;
                          //SelAttributes.Style:=Styl;
                          //SelLength:=0;
                          //StartPos:=SelStart+Length(mot);
                          inc(Result); // < ici le comptage 
                          StartPos:=FoundAt+Length(mot);
                          FoundAt:=FindText(mot, StartPos, ToEnd, [stMatchCase]);
                    end;
              end;
    end; // NombreDOccurrences
    ... et cette fonction te reverra le nombre de fois que mot est présent sans en modifier la couleur ... mais tu peux aussi conserver la procedure qui change les couleurs en la modifiant de sorte qu'une var Compteur te renvoie le nombre d'occurrences tout en modiant les couleurs.

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

  5. #5
    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,

    Compte tenu de la lenteur du chargement préalable du texte dans un RichEdit ... voici du code plus rapide où je lis le fichier-source par lots de 50 lignes suivies chaque fois d'un appel à la function NbOccurences( mot, Texte : string) : integer; pour incrémenter le comptage :
    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 NbOccurences( mot, Texte : string) : integer;
      var      pCherche, pTexte, pCourant : PChar;
      begin    // Initialisations :
               Result:=0;
               pCherche:=PChar(mot);
               pTexte:=PChar(Texte);
               // Démarrage au début du texte
               pCourant:=pTexte;
               // Recherches et comptage
               pCourant:=StrPos(pCourant,pCherche);
               while pCourant<>nil do
               begin inc(Result); // comptage
                     pCourant:=pCourant+length(mot);
                     pCourant:=StrPos(pCourant,pCherche);
               end;
      end;
     
    function LireFichierEtCompterOccurrences(NomFichier, mot : string) : integer;
      var    S,LotDeLignes : String; nbLignes : integer;
             F  : Text;
      begin  Result:=0; nbLignes:=0;
             Assign(F, NomFichier);
             Reset(F);
             if IoResult <> 0
             then begin ShowMessage('Fichier incorrect'); EXIT; end;
             LotDeLignes:='';
             while (not EoF(F)) do
             begin ReadLn(F, S);
                   if S <> '' then // Comptage
                   begin Inc(nbLignes); LotDeLignes:=LotDeLignes + S; end;
                   if nbLignes mod 50 = 0 then
                   begin Result:=Result+NbOccurences( mot, LotDeLignes);
                         LotDeLignes:='';
                   end;
             end;
             // Comptage dans dernier lot
             if LotDeLignes <> ''
             then Result:=Result+NbOccurences( mot, LotDeLignes);
             Close(F);
      end;
     
    // Utilisation :
     
    procedure TForm1.btnOccurrencesClick(Sender: TObject);
    var       Texte, mot : string; NbOcc : integer; SL : TStringList;
    begin     // 1) Mini-test de bon fonctionnement :
              //mot:='Tagada';
              //Texte:=mot+' sldkjhfsdf '+mot+' sldkjhfsdf '+mot+' '+#13#10;
              //Texte:=Texte+Texte+Texte+Texte+Texte;
              //RichEdit1.lines.Add(Texte);
              //nbOcc:=NbOccurences( mot, Texte);
              //ShowMessage(intToStr(nbOcc)); Ok pour ce mini-tets
     
              // 2) Test avec chargement direct d'un RichEdit via LoadFromFile
              //Chrono.Top;
              //RichEdit2.lines.LoadFromFile(RepAppli+'Test0.mem');
              //RichEdit1.lines.Add('LoadFromFile En : '+Chrono.mis); 
              //<  mis 3075 ms avec fichier 'Test0.mem' de 6.878 Mo 
     
              // 3 ) Test 
              //Chrono.Top;
              mot:='page';
              nbOcc:=LireFichierEtCompterOccurrences(RepAppli+'Test0.mem', mot);
              RichEdit1.lines.Add('Trouvé : '+intToStr(nbOcc)+' x '+mot);
              //RichEdit1.lines.Add('En : '+Chrono.mis);
              //< Trouvé : 1000 x page En : 410 ms dans fichier de 6.878 Mo 
              // soit 7,5 x+rapide que le chargement direct dans le RichEdit
    end;
    // Rem : le chronomètre placé en commentaire et dont le code ne figure pas
    // ici est tout simplement basé sur l'utilisation de GetTickCount.
    Résultats d'un test de vitesse avec un fichier de 1000 x 60 lignes de 115 caractères (6.878 Mo, équivaut à un texte imprimé recto-verso sur les 1000 pages d'un paquet de 500 feuilles A4, épais de 5 cm et dont chaque page comporte le mot 'page' de la pagination) :
    1) Pour le chargement des 60 000 lignes directement dans un RichEdit via LoadFromFile : mis 3075 ms sans comptage des mots.
    2) Lecture et comptage des mots avec la function LireFichierEtCompterOccurrences() : mis 410 ms (16,77 Ko/ms) ... soit 7,5 fois plus rapide que le chargement précédent sans comptage (Pentium III à 1,13 GHz)

    A noter qu'en plus du gain de vitesse la méthode est économe en mem-vive (traitement par lots de lignes) et utilisable même dans un cas où le fichier-source ne pourrait pas être chargé entièrement en mem-vive.

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

  6. #6
    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 délestage
    --------------------------------------------------------------------------------

    salut,
    merci vraiment.
    joyeux noel

    dit pour le code:

    RepAppli est déclaré dans quel unité?

    nbOcc:=LireFichierEtCompterOccurrences(RepAppli+'Test0.mem', mot);


    merci a+
    La patience est un Chemin d'or

  7. #7
    Rédacteur/Modérateur
    Avatar de ero-sennin
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2005
    Messages
    2 965
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2005
    Messages : 2 965
    Points : 4 935
    Points
    4 935
    Par défaut
    Re,

    RepAppli n'est qu'une variable dans laquelle est contenu le chemin du répertoire de l'application pour qu'il puisse charger son fichier de test ...

    Dans son cas, RepAppli contient celà :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    var
    RepAppli:String;
    begin
    //...
    RepAppli:=ExtractFilePath(ParamStr(0));
    //...
    end;
    A la place de RepAppli, tu peux mettre :C:\Toto\tata\ ce qui correspond au dossier ou se trouve le fichier texte... (ici Test0.mem)

    A+

  8. #8
    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
    si tu as utlisé le code que j'ai proposé avant, j'ai fait quelque modif
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Tient, j'ai aussi fait une fonction de recherche dans un fichier pour répondre à ce sujet "Parcourir un fichier texte sans charger le fichier"

    J'ai écrit SearchStringInFile et SearchStringInBigFile, qui sont aussi rapide qu'UltraEdit pour la recherche de chaine ... voir ICI aussi

    Citation Envoyé par Gilbert Geyer
    A noter qu'en plus du gain de vitesse la méthode est économe en mem-vive (traitement par lots de lignes) et utilisable même dans un cas où le fichier-source ne pourrait pas être chargé entièrement en mem-vive.
    Euh, cette ligne est très couteuse en temps et en mémoire, car implique une réallocation (50 fois de suite ) d'une chaine, de plus en plus grosse ... mieux vaut une lecture via un buffer direct (en sachant que ReadLn utilise un buffer de lecture, et doit faire un parsing des retours charriot, on peut économiser bcp)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    LotDeLignes:=LotDeLignes + S;
    Tu pourrais Gilbert Geyer, tester SearchStringInFile avec ton fichier et ta machine (comparons ce qui est comparable), j'ai fait un fichier de 7.4Mo, contenant 882 fois le mot "page", mais sur un PIV 3Gz 4MoRAM, ...

    LireFichierEtCompterOccurrences = 347 à 353 ms
    SearchStringInFile (CaseSensitive True) = 105 à 108 ms (sans OffSets)
    SearchStringInFile (CaseSensitive False) = 129 à 133 ms
    SearchStringInBigFile = 62 à 64 ms

    Pourquoi tant de différence ente "...File" et "...BigFile" c'est à cause de EOF qui est nettement plus lent que le test sur iReaded, ... et aussi à cause de BlockRead qui encapsule via un pointeur de procédure la fonction FileRead c'est la fonction qui presque au plus bas niveau (elle appelle selon directive de compilaion API Windows ReadFile ou API Linux __read, a part ASM on peut pas faire mieux)

    l'existence de l'option CaseSensitive fait perdre 10ms environ, son activation coute 30ms .

    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
    85
     
    {* -----------------------------------------------------------------------------
    la Fonction SearchStringInFile Permet de Chercher une Chaine dans Fichier, la fonction renvoi le nombre d'occurence, et peu renvoyer un tableau contenant le premier octet de chaque occurence dans le fichier
    @param FileName Chaine contenant le nom du Fichier
    @param SearchString Chaine à chercher dans le fichier
    @param OffSets Tableau d'Entier qui contiendra les positions de occurences trouvés
    @param KeepOffSet Boolean True rempli OffSets, False, ne rempli pas OffSets
    @return Nombre d'occurence Trouvé
    ------------------------------------------------------------------------------ }
    function SearchStringInFile(const FileName: string; SearchString: string; out OffSets: TIntegerDynArray; KeepOffSet: Boolean = False; CaseSensitive: Boolean = True): Integer;
    const
       BUF_SIZE: Integer = 1024;
    var
       FileToSearch: file;
       SearchBuf: array of Char;
       iSearchBufPos, iSearch, iMark, iCountFound, iRememberFound, iReaded: Integer;
       SearchLen: Integer;
       AmtTransferred: Integer;
       FileModeCopy: Byte;
    begin
       Result := 0;
       iReaded := 0;
     
       SetLength(SearchBuf, BUF_SIZE);
       SearchLen := Length(SearchString);
       if not CaseSensitive then
         SearchString := SysUtils.UpperCase(SearchString);
     
       FileModeCopy := FileMode;
       FileMode := SysUtils.fmOpenRead;
       try
         AssignFile(FileToSearch, FileName);
         Reset(FileToSearch, 1);
         try
            iCountFound := 0;
     
            while not Eof(FileToSearch) do
            begin
               BlockRead(FileToSearch, SearchBuf[0], BUF_SIZE, AmtTransferred); // [0] parce que c'est un tableau dynamique
               iRememberFound := iCountFound;
               iSearchBufPos := 0;
     
               while iSearchBufPos < AmtTransferred do
               begin
                  // Comparaison Octet par Octet de la chaine recherchée
                  for iMark := iCountFound + 1 to SearchLen do
                  begin
                     iSearch := iSearchBufPos + iMark - iRememberFound - 1;
                     if iSearch >= AmtTransferred then
                        Break;
     
                     if (CaseSensitive and (SearchBuf[iSearch] = SearchString[iMark]))
                     or (not CaseSensitive and (UpCase(SearchBuf[iSearch]) = SearchString[iMark])) then
                     begin
                        Inc(iCountFound);
     
                        if iCountFound >= SearchLen then
                        begin
                           Inc(Result);
                           if KeepOffSet then
                           begin
                              SetLength(OffSets, Length(OffSets) + 1);
                              OffSets[High(OffSets)] := iReaded + iSearchBufPos - iRememberFound;
                           end;
                           iCountFound := 0;
                           iRememberFound := 0;
                           Break;
                        end;
                     end else begin
                        iCountFound := 0;
                        iRememberFound := 0;
                        Break;
                     end;
                  end;
                  Inc(iSearchBufPos, iCountFound + 1);
               end;
               Inc(iReaded, AmtTransferred);
            end;
         finally
            CloseFile(FileToSearch);
         end;
       finally
         FileMode := FileModeCopy;
       end;
    end;
    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
    {* -----------------------------------------------------------------------------
    la Fonction SearchStringInBigFile Permet de Chercher une Chaine dans Fichier de plus de 2Go, la fonction renvoi le nombre d'occurence, et peu renvoyer un tableau contenant le premier octet de chaque occurence dans le fichier
    @param FileName Chaine contenant le nom du Fichier
    @param SearchString Chaine à chercher dans le fichier
    @param OffSets Tableau d'Entier qui contiendra les positions de occurences trouvés
    @param KeepOffSet Boolean True rempli OffSets, False, ne rempli pas OffSets
    @param Threshold Si le nombre de chaine trouvé atteind ce nombre, la Recherche s'arrête
    @return Nombre d'occurence Trouvé
    ------------------------------------------------------------------------------ }
    function SearchStringInBigFile(const FileName, SearchString: string; out OffSets: TIntegerDynArray; KeepOffSet: Boolean = False; Threshold: Integer = MaxInt): Integer;
    const
       BUF_SIZE: Integer = 1024;
    var
       FileToSearch: Integer;
       FileLength: Int64;
       SearchBuf: array of Char;
       iSearchBufPos, iSearch, iMark, iCountFound, iRememberFound, iReaded: Integer;
       SearchLen: Integer;
       AmtTransferred: Integer;
    begin
       SetLength(SearchBuf, BUF_SIZE);
       SearchLen := Length(SearchString);
     
       Result := 0;
       iReaded := 0;
       FileToSearch := FileOpen(FileName, fmOpenRead);
       if FileToSearch < 0 then
         Exit;
       try
          FileLength := FileSeek(FileToSearch, 0, FILE_END);
          FileSeek(FileToSearch, 0, FILE_BEGIN);
     
          iCountFound := 0;
     
          while iReaded < FileLength do
          begin
             AmtTransferred := FileRead(FileToSearch, SearchBuf[0], BUF_SIZE); // [0] parce que c'est un tableau dynamique
             iRememberFound := iCountFound;
             iSearchBufPos := 0;
     
             while iSearchBufPos < AmtTransferred do
             begin
                // Comparaison Octet par Octet de la chaine recherchée
                for iMark := iCountFound + 1 to SearchLen do
                begin
                   iSearch := iSearchBufPos + iMark - iRememberFound - 1;
                   if iSearch >= AmtTransferred then
                      Break;
     
                   if SearchBuf[iSearch] = SearchString[iMark] then
                   begin
                      Inc(iCountFound);
     
                      if iCountFound >= SearchLen then
                      begin
                         Inc(Result);
                         if KeepOffSet then
                         begin
                            SetLength(OffSets, Length(OffSets) + 1);
                            OffSets[High(OffSets)] := iReaded + iSearchBufPos;
                         end;
                         if iCountFound = Threshold then
                           Exit;
     
                         iCountFound := 0;
                         iRememberFound := 0;
                         Break;
                      end;
                   end else begin
                      iCountFound := 0;
                      iRememberFound := 0;
                      Break;
                   end;
                end;
                Inc(iSearchBufPos, iCountFound + 1);
             end;
             Inc(iReaded, AmtTransferred);
          end;
       finally
          FileClose(FileToSearch);
       end;
    end;
    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

  10. #10
    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 salut
    super ton code
    salut

    ton code j'aimerais mieux le comprendre.
    peux-tu m'indiquer la demarche à suivre pour l'employer dans mon code.

    merci
    La patience est un Chemin d'or

  11. #11
    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,

    Bigey3 a écrit : RepAppli est déclaré dans quel unité?
    ... excuses j'avais oublié que RepAppli était logé dans mon unité "caisse à outils" qui m'évite de réécrire à chaque fois ExtractFilePath() ... mais Ero-sennin t'a bien mis sur la piste à la seule différence que chez moi RepAppli:=ExtractFilePath(Application.ExeName);

    ShaiLeTroll a écrit : Euh, cette ligne est très couteuse en temps et en mémoire, car implique une réallocation (50 fois de suite )...
    ... Effectivement, lors des tests javais commencé avec un if nbLignes mod 1000 et je me suis rendu compte que plus je diminuais cette valeur et plus ça allait vite ... mais il ne m'est pas venu à l'idée de remplacer ce traitement par série de lignes par un traitement en rafale.

    ShaiLeTroll a écrit : Tu pourrais Gilbert Geyer, tester SearchStringInFile avec ton fichier et ta machine...
    ... Ok je posterai les résultats ici.

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

  12. #12
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par bigey3 Voir le message
    ton code j'aimerais mieux le comprendre.
    peux-tu m'indiquer la demarche à suivre pour l'employer dans mon code.
    merci
    Pour reprendre l'exemple avec LireFichierEtCompterOccurrences adapté pour SearchStringInBigFile

    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
    procedure TForm1.btnOccurrencesClick(Sender: TObject);
    var
      mot : string; 
      NbOcc, iOff  : integer; 
      OffSets: TIntegerDynArray; // faut ajouter Types dans les uses;
    begin              
       mot := 'page';
       nbOcc := SearchStringInBigFile(RepAppli+'Test0.mem', mot, OffSets,  True);
       RichEdit1.lines.Add('Trouvé : '+intToStr(nbOcc)+' x '+mot);
     
       RichEdit1.Lines.BeginUpdate();
       try
          for iOff := Low(OffSets) to High(OffSets) do
             RichEdit1.Lines.Add(Format('Position n°%d : %d octets', [iOff, OffSets[iOff]]));
       finally
          RichEdit1.Lines.EndUpdate();
       end;
    end;
    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

  13. #13
    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 salut
    salut

    mon appli compte le nombre d'occurence de plusieurs mots.

    en plus cette recherche se fait après le chargement du fichier concerné.

    là je ne vois pas trop comment faire la jonction avec ton code.
    indique moi la demarche exacte si tu veux bien.


    merci

    a+
    La patience est un Chemin d'or

  14. #14
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ma fonction permet de chercher un mot dans un fichier, je n'ai fait que proposer une équivalence à LireFichierEtCompterOccurrences ...

    Je pensais que tu voulais faire une statistique, donc un calcul, pourquoi vouloir afficher (charger) le fichier ? et d'ailleurs, je ne connais pas ton code, ... je ne peux donc pas me prononcer à ce sujet...

    Ensuite, pour chercher plusieurs mots, suffit de faire une boucle sur une TStringList appelant plusieurs fois SearchStringInBigFile (diffcile de faire une fonction cherchant plusieurs mots à la fois avec l'algo via buffer ... si j'ai le temps ...)
    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

  15. #15
    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,

    1) J'ai voulu tester SearchStringInFile() de ShaiLeTroll mais comme j'ai Delphi5 j'ai les messages d'erreur suivants :
    - pour le Types dans le Uses : [Erreur fatale] uOccurrences.pas(7): Fichier non trouvé : 'Types.dcu' donc j'ai supprimé le Types.

    - ensuite pour la ligne : function SearchStringInFile(const FileName: string; SearchString: string; out OffSets: TIntegerDynArray; KeepOffSet: Boolean = False; CaseSensitive: Boolean = True): Integer; j'ai eu <[Erreur] uOccurrences.pas(192): Identificateur non déclaré : 'TIntegerDynArray'

    ... j'ai donc remplacé out OffSets: TIntegerDynArray par var OffSets: array of Integer;

    ... mais ensuite pour la ligne SetLength(OffSets, Length(OffSets) + 1); j'ai eu le messge <[Erreur] uOccurrences.pas(245): Types incompatibles
    ... Y'a-t-il une astuce pour contourner ce problème histoire de pouvoir faire les tests (car SearchStringInBigFile est similaire sur ce point) ?

    2) Du coup j'ai fait un test avec la méthode utilsée dans Test.zip de Edam que j'ai adaptée et utilisée comme suit, et où la var MotsCibles : array of string sert en entrée pour désigner les mots ciblés par le comptage, et en sortie pour afficher le résultats des comptages, et comme sa procédure scanne une string j'ai chargé le fichier dans un StringStream pour lui envoyer la DataString :
    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
     
    function ChargerFichierDansSS(const NomFichier : string; var SS : TStringStream) : boolean;
      var    FS : TFileStream;
      begin  try
                FS := TFileStream.Create(NomFichier, fmOpenRead);
                SS.CopyFrom(FS, FS.Size);
             except
                Result:=False; ShowMessage('Pas pu charger '+NomFichier);
                FS.Free; EXIT;
             end;
             FS.Free;
             Result:=True;
      end;
     
    procedure TestEdam(Texte : string; var MotsCibles : array of string);
    var       i,j,m,n:integer;
    begin
         for i:=Low(MotsCibles) to High(MotsCibles) do
           begin
             n:=0;
             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;
             MotsCibles[i]:=MotsCibles[i]+' Trouvé : '+inttostr(n)+' fois';
           end;
    end;
     
    // Utilisation : 
     
    procedure TfrmOcc.btnTestEdamClick(Sender: TObject);
    var       Mots : array of string; i : integer;
              SS : TStringStream; Chargement : boolean;
    begin     Chrono.Top;
              SS := TStringStream.Create('');
              Chargement:=ChargerFichierDansSS(RepAppli+'Test0.mem', SS);
              redTrace.lines.Add('StringStream chargé en : '+Chrono.mis);
              if Chargement then
              begin SetLength(Mots,1);
                    Mots[0]:='page';
                    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;
    Résultats :pour test de vitesse avec le fichier de 1000 x 60 lignes de 115 caractères (6.878 Mo) comportant 1000 fois le 'page' le reste étant du texte aléatoire :

    - StringStream chargé en : 69 ms
    - TestEdam : chargé et compté en : 279 ms soit 1,47 fois plus rapide que mon code d'Hier 12h05 (Pentium III à 1,13 GHz)

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

  16. #16
    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,

    En final j'ai trouvé la soluce pour pouvoir tester les functions de ShaiLeTroll sous Delphi-5 suffit d'y apporter les retouches suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Type tAOI = Array Of Integer; // < type à déclarer hors des functions d'appel
    
    function SearchStringInFile(const FileName: string; SearchString: string; var OffSets: tAOI; KeepOffSet: Boolean = False; CaseSensitive: Boolean = True): Integer;
    
    function SearchStringInBigFile(const FileName, SearchString: string; var OffSets: tAOI; KeepOffSet: Boolean = False; Threshold: Integer = MaxInt): Integer;
    ... et rien d'autre à modifier dans le reste du code de ces functions.

    Pour les tests je les ai utilisées comme suit
    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
     
    procedure TfrmOcc.btnSearchStringInFileClick(Sender: TObject);
    var       mot : string; nbOcc : integer;
              OffS: tAOI;
    begin     Chrono.Top;
              mot:='page';
              nbOcc:=SearchStringInFile(RepAppli+'Test0.mem', mot, OffS, False, True);
              redTrace.lines.Add('Test SearchStringInFile : chargé et compté en : '+Chrono.mis);
              redTrace.lines.Add('Trouvé : '+intToStr(nbOcc)+' x '+mot);
    end;      
     
    procedure TfrmOcc.btnSearchStringInBigFileClick(Sender: TObject);
    var       mot : string; nbOcc : integer;
              OffS: tAOI;
    begin     Chrono.Top;
              mot:='page';
              nbOcc:=SearchStringInBigFile(RepAppli+'Test0.mem', mot, 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 des tests de vitesse avec le même fichier de 60 000 lignes utilisé lors de mes tests déjà cités dans cette discussion :
    - Test SearchStringInFile : chargé et compté en : 314 ms (à peu près du même ordre que TestEdam qui a mis 279 ms)
    - Test SearchStringInBigFile : chargé et compté en : 136 ms soit 2 fois plus rapide que TestEdam

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

  17. #17
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    La grosse différence entre SearchStringInBigFile et l'algo de Edam, c'est l'occupation mémoire, envion 1Ko contre un fichier totalement en mémoire, ...

    Ce qui est marrant c'est le peu de différence entre SearchStringInBigFile et SearchStringInFile, et la différence de temps assez flagrante, jusque parce que on utilise tel ou tel fonction de bas niveau ...
    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. #18
    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 code n'est fait ici que pour l'aidé à trouvé une solution, et aussi sur un fichier de petit taille;
    mais ShaiLeTroll à fait le nécessaire de donnée un code complet
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

  19. #19
    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,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ShaiLeTroll a écrit : La grosse différence entre SearchStringInBigFile et l'algo de Edam, c'est l'occupation mémoire, envion 1Ko contre un fichier totalement en mémoire, ...
    ... faut rendre à César ce qui appartient à César : l'algo originel de Edam était un simple exemple de faisabilité où la string de texte scannée était Memo1.text et c'est moi qui l'ai modifiée pour pouvoir faire les comptages sur la DataString du StringStream chargé totalement en mémoire.
    Alors de choses l'une :
    - si Bigey3 dispose d'une mem-vive suffisante pour charger ses 800 000 lignes de texte en mémoire (t'as combien de Go de mem ?) il pourra utiliser au choix n'importe lequel des codes proposés.

    - ou alors on pourrait continuer à modifier l'algo de Edam de façon à faire les comptages ligne par ligne c'est à dire en ne chargeant en mémoire qu'une seule ligne à la fois ... mais vu la rapidité de SearchStringInBigFile cela ne vaut peut-être pas le coup ... je dis peut-être en attendant la suite car Bigey3 veut faire du comptage sur toute une série de mot-cibles et l'algo de Edam permet de faire le comptage simultané avec plusieurs mot-cibles.

    Faudra faire des tests avec SearchStringInBigFile dans une boucle pour N-mots-cibles et comparer à l'algo d'Edam qui inclut déjà cette boucle : Bigey3 nous donnera certainement l'ordre de gandeur du N de N-mots-cibles.

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

  20. #20
    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
    j'ai 30 mot au plus à recherché
    La patience est un Chemin d'or

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

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