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

Free Pascal Discussion :

Optimisation d'une itération sur une String (enlever le dernier mot)


Sujet :

Free Pascal

  1. #1
    Invité
    Invité(e)
    Par défaut Optimisation d'une itération sur une String (enlever le dernier mot)
    Bonjour,

    sous Linux, je cherche à enlever le dernier mot d'une chaîne et à réitérer l'opération:
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
    Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    Lorem ipsum dolor sit amet, consectetur adipisicing
    [...]
    Dans la mesure où cette opération est réalisée un grand nombre de fois dans le OnDrawCell d'une TStringGrid, je cherche une méthode optimisée : rapidité max. (et fuites mémoire min. ... si on utilise des pointeurs).
    J'ai essayé par split et par diverses fonctions de SysUtils : efficaces mais lentes

    Une piste ? Merci Gilles
    Dernière modification par Invité ; 18/02/2013 à 10h27. Motif: Amélioration de la formulation

  2. #2
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 235
    Points : 506
    Points
    506
    Par défaut
    En considérant que les mots sont séparés par des espaces
    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
     
    program Test;
     
    {$mode objfpc}{$H+}
     
    uses
      Classes;
     
    procedure DelLastWord(var S: String);
    var
      I : Integer;
    begin
      I := Length(S);
     
      while (I > 0) and (S[I] = ' ') do
        Dec(I);
     
      while (I > 0) and (S[I] <> ' ') do
        Dec(I);
     
      while (I > 0) and (S[I] = ' ') do
        Dec(I);
     
      SetLength(S, I);
    end;
     
    function WithoutLastWord(const S: String) : String;
    var
      I : Integer;
    begin
      I := Length(S);
     
      while (I > 0) and (S[I] = ' ') do
        Dec(I);
     
      while (I > 0) and (S[I] <> ' ') do
        Dec(I);
     
      while (I > 0) and (S[I] = ' ') do
        Dec(I);
     
      Result := Copy(S, 1, I);
    end;
     
    var
      S : String;
    begin
     
      S := ' aaa   bb   cc ddd    eee f   ';
      while Length(S) > 0 do
      begin
        WriteLn('"', S, '"');
        DelLastWord(S);
      end;
     
      WriteLn;
     
      S := ' aaa   bb   cc ddd    eee f   ';
      while Length(S) > 0 do
      begin
        WriteLn('"', S, '"');
        S := WithoutLastWord(S);
      end;
     
      ReadLn;
    end.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    merci pour votre réponse. Dans mon cas, les espaces sont simples et il n'y en a pas au bout de la chaîne.

    Sur le principe, le parcours de la chaîne caractère par caractère à chaque itération n'est pas envisageable. C'est tout à fait fonctionnel mais beaucoup trop lent.

    Pour mesurer, j'ai un code de ce type :
    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
    procedure TForm1.Button1Click(Sender: TObject);
    {uses LCLIntf;
        StartTime, EndTime : TDateTime;
        sDiff : String;}
    var
       S : String;
    begin
        S := 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
        S := S + ' ' +S + ' ' +S;
      //Showmessage(intToStr(NombreDeMots(S)));
      //Showmessage(ChainePos(' ', S,NombreDeMots(S)));
        StartTime := LclIntf.GetTickCount;
        repeat
          S := DelLastWord1(S,' ');
        until S = '';
        EndTime := LclIntf.GetTickCount - StartTime;
        str(EndTime, sDiff);
        Label1.caption := sDiff;
    end;
    Donc après 207 itérations pour partir de ma chaîne initiale, le temps indiqué est 250 millisecondes. En valeur intrinsèque cela ne signifie rien. C'est une base de comparaison pour toutes les méthodes que j'utilise.

    Je dois déterminer en réalité où tronquer la chaîne pour simuler un DT_END-Ellipsis dans un Canvas (un Rect) donné.

    Pour l'instant mon approche est la suivante
    1. Déterminer si une méthode soustractive est nécessaire.. ou une méthode additive
    2. Appliquer la méthode retenue.

    Il est important que cette opération s'effectue rapidement si je veux obtenir un résultat fluide lorsque je réalise un ColSizing. Pour l'instant ce n'est pas le cas.

    Cordialement. Gilles
    Dernière modification par Invité ; 18/02/2013 à 20h22.

  4. #4
    Rédacteur/Modérateur
    Avatar de M.Dlb
    Inscrit en
    Avril 2002
    Messages
    2 464
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Avril 2002
    Messages : 2 464
    Points : 4 311
    Points
    4 311
    Par défaut
    Effectivement, sur une chaîne très longue, ca peut prendre "beaucoup" de temps. Si il y a un moyen de déterminer le nombre de caractères maximal affichable dans la colonne, il faudrait tronquer la chaîne à ce niveau là, puis appliquer la méthode "soustractive".
    M.Dlb - Modérateur z/OS - Rédacteur et Modérateur Pascal

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Citation Envoyé par wormful_sickfoot Voir le message
    Si il y a un moyen de déterminer le nombre de caractères maximal affichable dans la colonne, il faudrait tronquer la chaîne à ce niveau là".
    Non pas vraiment car l'affichage est en polices proportionnelles. Cependant, j'utilise une démarche "pifométrique" quasi-identique non pas sur les caractères mais sur les mots.
    Citation Envoyé par wormful_sickfoot Voir le message
    Effectivement, sur une chaîne très longue, ca peut prendre "beaucoup" de temps.
    Il n'y a pas nécessairement des chaînes vraiment longues mais une grande répétition du traitement.

    Actuellement je pratique comme cela :

    Je compare
    • la propriété FRowHeightMax de mon composant
    • et la hauteur d'un Canvas possédant la largeur de la colonne de la TStringGrid considérée à l'aide d'un DrawText sur la chaîne complète en "DT_CALCRECT or DT_WORDBREAK" qui ainsi ajuste automatiquement la hauteur du canvas à l'affichage du texte dans la fonte retenue.


    Je détermine ainsi le ratio sur la hauteur : FRowHeightMax / (Rect.Bottom-Rect.Top). Evidemment si la chaîne ne nécessite pas de traitement (>=100%), celui-ci s'arrête là. Mais si tel n'est pas le cas, je l'applique au nombre de mots de la chaîne. 70% de hauteur -> 70% du nombre total de mots. Evidemment cela reste approximatif...

    J'obtiens donc ainsi une chaîne tronquée (sTrunc). Je (re)calcule alors la hauteur du Canvas (DT_CALCRECT or DT_WORDBREAK) qui la contient:
    • si Rect.Bottom-Rect.Top < FRowHeightMax : j'ajoute* à sTrunc les mots tronqués un par un jusqu'à ce que Rect.Bottom-Rect.Top > FRowHeightMax
    • si Rect.Bottom-Rect.Top > FRowHeightMax : j'enlève* à sTrunc le dernier de ses mots un par un jusqu'à ce que Rect.Bottom-Rect.Top < FRowHeightMax

    *le dernier mot est toujours suivi de ...
    Pour l'instant, je réalise un Split de la phrase dans un TStrings. Et ensuite, il s'agit de reconstituer les chaînes tronquées à partir du Split... J'envisage d'utiliser les pointeurs. J'ai regardé du côté des Delphistes et je reste perplexe sur les réelles efficacité et faisabilité :

    J'hésite un peu à me lancer dans cette approche mais je le ferai sans garantie d'obtenir une meilleure performance à moins que quelqu'un me propose autre chose. D'où ma question sur ce forum.

    Pour l'instant, le système est assez performant si le nombre de cellules concernées est peu important. J'essaie d'augmenter la fluidité du ColSizing de la TStringGrid lorsque j'utilise cette approche de End_Ellipsis...même si évidemment je n'espère pas obtenir celle du DT_END_ELLIPSIS de Windows.

    Cordialement.
    Gilles
    Dernière modification par Domi2 ; 16/03/2013 à 06h22.

Discussions similaires

  1. [WD18] Metre une colonne d'une Table sur une ligne d'une autre Table
    Par Totophe2 dans le forum WinDev
    Réponses: 2
    Dernier message: 22/11/2013, 12h58
  2. probleme avec l'appui sur une touche sur une jframe ou jdialog
    Par jeanfeu dans le forum Agents de placement/Fenêtres
    Réponses: 1
    Dernier message: 05/08/2008, 16h14
  3. [VBA Excel] Appliquer une macro sur une celulle contenant une valeur
    Par tchauviere dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 21/01/2008, 10h21
  4. Réponses: 3
    Dernier message: 06/11/2007, 11h18
  5. Réponses: 3
    Dernier message: 16/01/2006, 16h02

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