En faite je saisie une chaine de 6 caractères alors que il faut 10 caractère, j'aimerais compléter cette chaine saisie de 6 caractères à 10, donc ajouter 4 espaces.
En faite je saisie une chaine de 6 caractères alors que il faut 10 caractère, j'aimerais compléter cette chaine saisie de 6 caractères à 10, donc ajouter 4 espaces.
2 méthodes :
1er : Sauf erreur (car je ne l'utilise pas souvent)
2 em :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 MonResultat := Format('%10s',MaSource);
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 MonResultat := StringOfChar(' ', 10 - Length(MaSource)) + Masource;
la 2éme réponse marche
Merci
2 em
le probleme c'est qu'il me met des espaces devant, il me les faut derriere
MonResultat := StringOfChar(' ', 10 - Length(MaSource)) + Masource;
MonResultat (4 espaces) 123456
alors qu il me faut
MonResultat 123456(4 espaces)
Ben en inversant les instructions :
Code : Sélectionner tout - Visualiser dans une fenêtre à part MonResultat := Masource + StringOfChar(' ', 10 - Length(MaSource));
j'avais fait plusieurs inversion mais cette là
ça marche
Merci
Salut,
Et une troisème façon :A+
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 while Length(MaSource)<10 do Masource:=' '+MaSource; // pour mettre les espaces au début ou bien while Length(MaSource)<10 do Masource:=MaSource+' '; // pour mettre les espaces à la fin
Presque ça, mais cela ne fonctionne qu'avec des nombres
Sinon, une version bcp plus rapide (3 fois plus que StringOfChar, et 10 fois plus qu'avec while)
Code : Sélectionner tout - Visualiser dans une fenêtre à part MonResultat := Format('%.10d', UnEntier);
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 SetLengthStuff(var S: string; NewLength: Integer; CharFill: Char); var OldLength: Integer; begin if Length(S) < NewLength then begin OldLength := Length(S); SetLength(S, NewLength); FillMemory(@S[OldLength + 1], NewLength - (OldLength), Byte(CharFill)); end; end; function CopyStuff(const S: string; NewLength: Integer; CharFill: Char): string; begin if Length(S) >= NewLength then begin Result := S; end else begin SetLength(Result, Length(S)); CopyMemory(@Result[1], @S[1], Length(S)); SetLengthStuff(Result, NewLength, CharFill); end; end;
Code : Sélectionner tout - Visualiser dans une fenêtre à part MonResultat := CopyStuff(Masource, 10, ' ');
Bonjour,
ShaiLeTroll a écrit :... je saute sur l'occasion pour râler : c'est un peu agaçant de savoir qu'on puisse de temps à autre créer des routines qui font pratiquement la même chose que les routines basiques comme StringOfChar mais "n" fois plus rapides que ces routines basiques. Cela donne l'impression que les routines standard ont été bâclées lors de leur conception.Sinon, une version bcp plus rapide (3 fois plus que StringOfChar, ...)
... en attendant on peut toujours utiliser "CopyStuff" en le renommant en "StringOfCharShail" pour s'en rappeller plus facilement. Merci ShaiLeTroll.
ShaiLeTroll a ajouté :... ça c'est moins surprenant mais si le while est utilisé juste pour parachever la valeur d'une saisie la lenteur relative s'effectue presque en temps masqué par celle de la saisie.... bcp plus rapide (... et 10 fois plus qu'avec while)
A+
Ce n'est pas StringOfChar qui est lent, mais le nombre d'allocation de chaine dû à la concaténation (SoF + S) ... c'est cela qui coute le plus ... d'ailleurs StringOfChar utilise FillChar, et FillMemory utilise aussi FillChar ... c'est juste qu'en utilisant CopyMemory on contrôle le nombre de chaines allouées durant l'opération ...
Sinon, les temps sont négligeables c'est pour quelques micro-secondes pour un seul appel ... mais dans des contraintes comme un serveur WEB, la rapidité des traitements de chaine est importante, et puis il est toujours bon de cherche la petite bête, d'ailleurs, voici encore plus rapide (15%)
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 function CopyAndFill(const S: string; NewLength: Integer; CharFill: Char): string; var OldLength: Integer; begin if Length(S) >= NewLength then begin Result := S; end else begin OldLength := Length(S); SetLength(Result, NewLength); CopyMemory(@Result[1], @S[1], OldLength); FillMemory(@Result[OldLength + 1], NewLength - (OldLength), Byte(CharFill)); end; end;
Re-bonjour,
Ok, vu.
... décidément on n'arrête pas le progrès : copié dans ma collection de perles : MerciShaiLeTroll : ... voici encore plus rapide (15%)
... mais pourquoi conserver CopyStuff alors que CopyAndFill est 15% fois plus rapide ?
A+
Parce que je viens juste de la pondre ...
Re-bonjour,
Ok, vu.
Et comme t'as dit :voiçi la version 2 de CopyAndFill...et puis il est toujours bon de cherche la petite bête...... ~ 8% plus rapide que CopyAndFill.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 procedure CopyAndFill2(var S: string; NewLength: Integer; CharFill: Char); var OldLength: Integer; begin if Length(S) >= NewLength then EXIT else begin OldLength := Length(S); SetLength(S, NewLength); CopyMemory(@S[1], @S[1], OldLength); FillMemory(@S[OldLength + 1], NewLength - (OldLength), Byte(CharFill)); end; end;
Par contre j'ai remarqué que StringOfChar est plus rapide (~1,51 fois plus rapide) tant qu'on n'a pas besoin de faire s:=s + StringOfChar() sinon avec la concaténation c'est plus lent (~ 1,43 fois fois plus lent).
A+
Re-bonjour,
Bigre une légère modif encore plus rapide :... CopyAndFill3 est environ 1,19 fois plus rapide que la VO CopyAndFill.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 procedure CopyAndFill3(var S: string; NewLength: Integer; CharFill: Char); var OldLength: Integer; begin OldLength := Length(S); //<<< if OldLength >= NewLength then EXIT else begin SetLength(S, NewLength); CopyMemory(@S[1], @S[1], OldLength); FillMemory(@S[OldLength + 1], NewLength - (OldLength), Byte(CharFill)); end; end;
A+
Normal, que cela soit plus rapide, comme je l'ai dit, tu changes la convention d'appel de fonction à procedure pour bénéficier du var, ... la fonction s'appelle CopyAndFill, donc elle doit copier puis remplir, ta fonction ne respecte plus cela, en fait, tu as refait SetLengthStuff finalement...
inutile de copier S dans S, mais CopyMemory normalement, se rend compte du truc, et donc ne fait rien ...
Code : Sélectionner tout - Visualiser dans une fenêtre à part CopyMemory(@S[1], @S[1], OldLength);
Sinon, pour le "Length(S)", tu as bien raison, une fois suffit !
ah, dans ton test de temps, si tu fais cela dans une boucle, pour bien tester, il faut remettre dans la chaine passé en paramètre à sa valeur d'origine, sinon, seul le 1er appel est bon ...
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 Value := '12345'; for k := 1 to 10 do begin QueryPerformanceCounter(StartTick); try for i := 1 to 100000 do begin SetLengthStuff(Value, 10, '0'); Value := '12345'; // cela prend du temps, mais au moins on garanti que SetLengthStuff doit REFAIRE vraiement son travail end; finally QueryPerformanceCounter(EndTick); QueryPerformanceFrequency(TickPerSec); TimeIteration := Round((EndTick - StartTick) / TickPerSec * 1000); MemoTimes.Lines.Add('SetLengthStuff N°' + IntToStr(k) + ' : ' + IntToStr(TimeIteration) + ' ms'); end; end; for k := 1 to 10 do begin QueryPerformanceCounter(StartTick); try for i := 1 to 100000 do begin Value := CopyStuff(Value, 10, '0'); Value := '12345'; // cela prend du temps, mais au moins on garanti que CopyStuff doit REFAIRE vraiement son travail end; finally QueryPerformanceCounter(EndTick); QueryPerformanceFrequency(TickPerSec); TimeIteration := Round((EndTick - StartTick) / TickPerSec * 1000); MemoTimes.Lines.Add('CopyStuff N°' + IntToStr(k) + ' : ' + IntToStr(TimeIteration) + ' ms'); end; end;
Re-bonjour,
Pour mes tests j'ai fait simple :Je viens de tester CopyAndFill4 (avec verrouillage du CopyMemory) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 procedure TForm1.btnCopyAndFillClick(Sender: TObject); // VO var s : string; begin Start:=getTickCount; for i:=1 to nbBoucles do begin s:='ab'; s:=CopyAndFill(s, 200, 'o'); end; edMis.text:='mis : '+intToStr(getTickCount - Start)+' ms'; // 703 ms pour nbBoucles=1000000 (Pentium III - 1,13 Ghz) end;... et avec :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 procedure CopyAndFill4(var S: string; NewLength: Integer; CharFill: Char); var OldLength: Integer; begin OldLength := Length(S); if OldLength >= NewLength then EXIT else begin SetLength(S, NewLength); //CopyMemory(@S[1], @S[1], OldLength); FillMemory(@S[OldLength + 1], NewLength - (OldLength), Byte(CharFill)); end; end;... Alors qu'avec CopyAndFill3 ça prenait 592 ms pour nbBoucles=1000000, CopyAndFill4 avec verrouillage du CopyMemory descend seulement à 571 ms pour nbBoucles=1000000 soit seulement 1,037 fois plus rapide que CopyAndFill3 ... mais ce qui est gagné est gagné.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 procedure TForm1.btnCopyAndFill3Click(Sender: TObject); var s : string; begin Start:=getTickCount; for i:=1 to nbBoucles do begin s:='ab'; CopyAndFill4(s, 200, 'o'); end; edMis.text:='mis : '+intToStr(getTickCount - Start)+' ms'; end;
Je crois qu'il n'y a plus rien à gratter pour améliorer.
A+
Bonjour,
Comme il n'y avait plus rein à gratter pour améliorer la vitesse, c'était dommage de laisser la procédure dans un état où elle ne permettait que d'affectuer des remplissages vers la droite ... donc voiçi la version 5 qui permet d'effectuer au choix le remplissage à gauche ('oooooABC') ou à droite ('ABCoooooo') à partir de s:='ABC' :
... Temps d'exécution sur la même bécane et toujours pour nbBoucles=1000000 sur s:='ab'; CopyAndFill5(s, 200, 'o', true/false); :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 procedure CopyAndFill5(var S: string; NewLength: Integer; CharFill: Char; Left : boolean); var OldLength: Integer; begin OldLength := Length(S); if OldLength >= NewLength then EXIT else begin SetLength(S, NewLength); if Left then begin CopyMemory(@S[NewLength - OldLength], @S[1], OldLength); FillMemory(@S[1], NewLength - OldLength-1, Byte(CharFill)); end else FillMemory(@S[OldLength + 1], NewLength - OldLength, Byte(CharFill)); end; end;
- pour remplissage à droite : mis 599 ms (soit 1009/599 = 1,68 fois plus rapide qu'un StringOfChar ajouté par concaténéation),
- pour remplissage à gauche : mis 854 ms (soit 1009/854 = 1,18 fois plus rapide que StringOfChar + concaténéation).
A+
bonjour
une petite question:
ce n'est pas la ré-invention de :
où "!" gère les espaces de début ou de fin ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part function FormatMaskText(const EditMask: string; const Value: string): string;
à plus
Salut,
Je ne connaissais pas FormatMaskText() dont tu dis qu'il gère les espaces de début ou de fin.
Mais CopyAndFill remplit avec n'importe quel caractère (y.c l'espace) et sur la logueur totale spécifiée une chaine donnée plus courte.
Exemple : si s:='ABC'; :
- alors CopyAndFill5(s, 200, 'o', True); renvoie s:='oooooABC'
- et CopyAndFill5(s, 200, 'o', False); renvoie s:= 'ABCoooooo'
c'est plus rapide que s:=s + StringOfChar()
A+
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager