Remplacer un caractère dans une chaîne

Résolu
Fred_Ca_Pulse
Messages postés
20
Date d'inscription
mercredi 15 mars 2006
Statut
Membre
Dernière intervention
19 juin 2008
- 16 août 2006 à 09:44
Fred_Ca_Pulse
Messages postés
20
Date d'inscription
mercredi 15 mars 2006
Statut
Membre
Dernière intervention
19 juin 2008
- 17 août 2006 à 11:05
Bonjour à tous

Pour otimiser mon code, j'ai voulu transformer en procédure la fonction de remplacement que j'utilise depuis longtemps déjà :

function CaractereRemplacer( CSource, CDestination : Char; const SChaine : String ) : String;
var
   ILong : Longint;
   Source, Dest : PChar;
begin
     ILong := Length( SChaine );
     SetLength( Result, ILong );
     Source := Pointer( SChaine );
     Dest := Pointer( Result );
     while ILong <> 0 do begin
           if Source^ = CSource
              then Dest^ := CDestination
              else Dest^ := Source^;
           Inc( Source );
           Inc( Dest );
           Dec( ILong );
     end;
end;


Son équivalent en procédure me semblait assez évident :

procedure CaractereRemplacerP( CSource, CDestination : Char; var SChaine : String );
var
   ILong : Longint;
   Source : PChar;
begin
     ILong := Length( SChaine );
     Source := Pointer( SChaine );
     while ILong <> 0 do begin
           if Source^ = CSource
              then Source^ := CDestination;
           Inc( Source );
           Dec( ILong );
     end;
end;

Mais, bien sûr , çà ne marche pas comme je voudrais  :
 j'obtiens une merveilleuse "Violation d'accès" lorqu'un caractère doit être remplacé par Source^ := CDestination

J'ai bien pensé à un problème de référencement des chaînes et j'ai donc ajouté la ligne
"UniqueString( SChaine );" en début de procédure :
çà fonctionne alors mais les performances ne sont plus à la hauteur !

Si vous avez une petite îdée sur la question, merci de m'en faire part.

25 réponses

DRJEROME
Messages postés
436
Date d'inscription
jeudi 9 janvier 2003
Statut
Membre
Dernière intervention
5 février 2015

16 août 2006 à 17:09
pouah...j'avais celle là...mais elle est certainement plus lente que toutes les vôtres (je vais tester) :
<hr />
procedure CaractereRemplacer1( CSource, CDestination : Char;var SChaine : String);
var
   Source,Dest : PChar;
   Resultat:String;
begin
     Resultat:=SChaine;
     Dest := @Resultat[1];
     Source := @SChaine[1];
     while Source^<>^@ do
     begin
           if Source^ = CSource then Dest^ := CDestination;
           Inc( Source );
           Inc( Dest);
     end;
     SChaine:=Resultat;
end;
<hr />

DrJerome 
0
DRJEROME
Messages postés
436
Date d'inscription
jeudi 9 janvier 2003
Statut
Membre
Dernière intervention
5 février 2015

16 août 2006 à 17:27
sinon celle de Cirec peut se transformer avec des "var"  :
<hr />
Procedure CaractereRemplacer( CSource, CDestination : Char; var SChaine : String; var result : String );
var
   ILong : Longint;
   Source, Dest : PChar;
begin
     ILong := Length( SChaine );
     SetLength( Result, ILong );
     Source := Pointer( SChaine );
     Dest := Pointer( Result );
     while ILong <> 0 do begin
           if Source^ = CSource
              then Dest^ := CDestination
              else Dest^ := Source^;
           Inc( Source );
           Inc( Dest );
           Dec( ILong );
     end;
end;
<hr />

DrJerome
0
DRJEROME
Messages postés
436
Date d'inscription
jeudi 9 janvier 2003
Statut
Membre
Dernière intervention
5 février 2015

16 août 2006 à 17:30
on peut aussi transformer la mienne ainsi :
<hr />
procedure CaractereRemplacer1( CSource, CDestination : Char;var SChaine : String; var Resultat:String);
var
   Source,Dest : PChar;
begin
     Resultat:=SChaine;
     Dest := @Resultat[1];
     Source := @SChaine[1];
     while Source^<>^@ do
     begin
           if Source^ = CSource then Dest^ := CDestination;
           Inc( Source );
           Inc( Dest);
     end;
end;
<hr />
mais j'ai la flemme de tester tout ça (je vais chez le dentiste)

à toute à l'heure ;)

DrJerome
0
Fred_Ca_Pulse
Messages postés
20
Date d'inscription
mercredi 15 mars 2006
Statut
Membre
Dernière intervention
19 juin 2008

16 août 2006 à 17:32
Bonjour 360948 f0xi

Cà m'a l'air plein de bonnes idées ...
mais chez moi çà plante sur une "Erreur de vérification d'étendue" à la fin de la chaîne S[i] lorsque i = Length + 1
... j'ai l'option "Vérification des limites" activée !

En la désactivant çà marche ...
En fait les options de compilation changent énormément la performance d'exécution.
Je vais étudier un peu plus la chose.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Fred_Ca_Pulse
Messages postés
20
Date d'inscription
mercredi 15 mars 2006
Statut
Membre
Dernière intervention
19 juin 2008

17 août 2006 à 11:05
Rebonjour à tous, voilà ma petite synthèse à moi :


- le passage de fonction en procédure n'est pas concluant : bug d'accès à la variable dans certains cas, et pas de gain de performance
- on peut visiblement faire mieux que ma fonction initiale ( merci f0xi )
- les options de compilations "Vérifier les limites" et "Verifier les débordements" influent non seulement sur les erreurs détectées, mais aussi sur les performances


J'ai donc écrit une nouvelle procédure inspirée de celle de f0xi mais évitant le problème de vérification et je l'ai comparée à ma fonction initiale selon les options de compilation :


function CaractereRemplacer1( CSource, CDestination : Char; const SChaine : String ) : String;
var
   ILong : Longint;
   Source, Dest : PChar;
begin
     ILong := Length( SChaine );
     SetLength( Result, ILong );
     Source := Pointer( SChaine );
     Dest := Pointer( Result );
     while ILong <> 0 do begin
           if Source^ = CSource
              then Dest^ := CDestination
              else Dest^ := Source^;
           Inc( Source );
           Inc( Dest );
           Dec( ILong );
     end;
end;


function CaractereRemplacer2( CSource, CDestination : Char; const SChaine : String ) : String;
var
   ILong, I : Longint;
   PDest : PChar;
begin
     ILong := Length( SChaine );
     SetLength( Result, ILong );
     if ILong > 0 then
        begin
        PDest := Pointer( Result );
        I := 1;
        repeat
              PDest[ 0 ] := SChaine[ I ];
              if PDest[ 0 ] = CSource
                 then PDest[ 0 ] := CDestination;
              Inc( PDest );
              Inc( I );
        until I > ILong;
        end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
   F, A, B, V1, V2 : Int64;
   STest, SResult1, SResult2 : String;
   I : Longint;
begin
     Windows.QueryPerformanceFrequency( F );
     STest := 'Test de remplacement de caractères';
     Windows.QueryPerformanceCounter( A );
     for I := 1 to 10000000 do
         SResult1 := CaractereRemplacer1( 'e', 'o', STest );
     Windows.QueryPerformanceCounter( B );
     V1 := Trunc( ( B - A ) / F * 1000 );
     Windows.QueryPerformanceCounter( A );
     for I := 1 to 10000000 do
         SResult2 := CaractereRemplacer2( 'e', 'o', STest );
     Windows.QueryPerformanceCounter( B );
     V2 := Trunc( ( B - A ) / F * 1000 );     ShowMessage( 'Résultat V1 ' + SResult1 + #13 + 'Temps V1 ' + IntToStr( V1 ) + #13 +                  'Résultat V2 ' + SResult2 + #13 + 'Temps V2 ' + IntToStr( V2 ) );
end;


Je tourne sous XP SP2 avec Delphi 7 sur un Pentium D 2.8 Ghz.
Voici mes résultats :





<colgroup>
<col style=\"WIDTH: 60pt\" span=\"5\" width=\"80\" />
</colgroup>

----

,
V1,
V2,
V1,
V2,

----

L+D,
4431,
3668,
1.00,
1.00,

----

D,
4456,
4257,
1.01,
1.16,

----

L,
3702,
4144,
0.84,
1.13,

----

Rien,
3761,
3319,
0.85,
0.90


L+D = activation Limites + Débordements
D = activation seulement des Débordements
L = activation seulement des Limites
Rien = ni l'un, ni l'autreLa meilleure est bien la V2, mais avec des fluctuations étranges lors de l'activation de seulement une des 2 options testées.
Voilà une bien étrange conclusion pour une histoire débutée sur une simple question d'algorithmie.
Enfin, je suis déjà content : j'ai toujours une fonction, mais elle va plus vite !
...
Le problème suivant sera de déterminer combien de temps il va falloir que cette nouvelle fonction tourne en continue pour justifier le temps passé à la modifier ?
Avis aux amateurs ... A+
0