LIRE UNE SOUS-CHAINE DANS UNE CHAINE CONTENANT DES SÉPARATEURS.

f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 - 9 déc. 2005 à 23:06
kurayamino Messages postés 3 Date d'inscription samedi 21 décembre 2002 Statut Membre Dernière intervention 18 décembre 2005 - 18 déc. 2005 à 11:40
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/35004-lire-une-sous-chaine-dans-une-chaine-contenant-des-separateurs

kurayamino Messages postés 3 Date d'inscription samedi 21 décembre 2002 Statut Membre Dernière intervention 18 décembre 2005
18 déc. 2005 à 11:40
je suis loin d'etre un pro en Delphi, mais bon, moi j'ai codé la fontion comme ci dessous :

function GetTok(Chaine: String; Position: byte; Separateur: Char):String;
var
i:byte;
temp:string;
begin

{ initialise les variables }
i := 1;
temp := chaine;

{ si 1er token }
if position = 1 then begin
{ si la fin de la chaine est un separateur }
if pos(separateur,chaine) > 0 then begin
result := copy(chaine,1,pos(separateur,chaine)-1);
exit;
{ sinon }
end else begin
result := chaine;
exit;
end;
{ sinon }
end else begin
{ effacer le 1er token jusqu'a atteindre la position voulue }
{ utilisation d'une variable temp à la place de chaine }
while i < position do begin
delete(temp,1,pos(separateur,temp));
i := i + 1;
end;
{ si la fin de la chaine est un separateur }
if pos(separateur,temp) > 0 then begin
result := copy(temp,1,pos(separateur,temp)-1);
exit;
{ sinon }
end else begin
result := temp;
exit;
end;
end;

end;
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
14 déc. 2005 à 11:12
@Ahmed : desolé j'avais pas vus l'une de tes reponses...

Foxi->Désolé de ne pas avoir envisagé des fichiers spéciaux comportant des séparateurs à plusieurs caractères ... Pour ce qui est de copier une fonction d'une unit, celà me semble extrêment intéressant et devrait faire l'objet d'un petit tutoriel de ta part sur les pièges à éviter.

pour les separateurs multicaractere je pense en premier lieu au fin de ligne (EOLN) dans un fichiers texte par exemple (#13+#10), chainepos peut permettre de renvoyer toute une ligne d'un tel fichier.
mais egalement pour les fichiers binaire, qui par exemple utilise un h0000 ou encore h00000000 pour separer certain element tel par exemple les IdTag des MP3 ect...
ce qui permet a ChainePos d'avoir une utilitée réellement plus vaste.

un exemple concret, on recupere dans un stream la partie du fichier binaire qui nous interresse, et un simple apel a ChainePos nous permet de recuperer directement ce qui nous interresse et la mon astuce "const posi : cardinal = 1" vas nous servir.

Avec READ, on recupere un Char ou un tableau ... string n'est rien d'autre qu'un type PChar "humanisé".

admettons que le stream contient plusieurs partie avec données a taille variable et separateurs egalement variable.

admettons :
SPart (pchar) = ABCD #0#0 EF #0#0#0#0 GHI #2 JKLM #0#0 NOP #32#32 QRS

recuperons les elements grace a ChainePos :
ABCD = ChainePos(#0+#0, SPart)
EF = ChainePos(#0+#0, SPart, 2)
GHI = ChainePos(#0+#0+#0+#0, SPart, 2)
JKLM = ChainePos(#2, SPart, 2)
NOP = ChainePos(#32+#32, ChainePos(#0+#0, SPart, 5)) << 5 parce que #0#0#0#0 est consideré comme deux separateur #0#0 et #0#0 avec un element vide au milieu.
QRS = ChainePos(#32+#32, ChainePos(#0+#0, SPart, 5), 2) << idem que pour NOP

tout cela sans toucher au stream ou a la position de l'offset de lecture dans le stream.

vus les performances que j'ai obtenus avec ma version de ChainePos utilisé dans un Listbox pour transformer le texte affiché par rapport au texte contenus ... je pense que ça reste carrement correct (je rapel que 100000 requette a ma methode prennent environ 63ms en moyenne seulement).

bon la l'exemple est bidon... mais l'utilisation de chainepos de cette façon reste une possibilitée a prendre en compte.

par contre les autre proposition a separateur uni-caractere ne peuvent pas etendre leur utilisation jusque la.

donc comme l'a dit JLen100 a propos de ma methode, non seulement plus generale mais egalement a mon sens trés polyvalente. ce qui est forcement un plus car elle peut etre utilisée la ou on s'y attend le moins.
Tu prend notre ChainePos et Format et tu as quasiment plus besoin des autres fonctions de traitements de chaines de caractere. (qu'elle pretention! hihihi)

d'ailleur je m'etonne qu'une fonction aussi pratique que ChainePos n'existe pas dans delphi nativement. dans php il existe une fonction a peu prés equivalente GetWord() il me semble.

(vend methodes delphi pas cher ... bon etat general ... prix a negocier ... hehehe)
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
14 déc. 2005 à 10:35
-->f0xi
pour le portage ce que tu dis est vrai tant que tu n'appelles pas de ressource du bios ou d'entrées sorties.
pour le timer je t'expliquerais ça en message perso vu que ce n'est pas le sujet ici (la solution c'est de travailler en asynchrone pour ne jamais attendre et de traiter l'information quand elle est complète).
mon propos c'était simplement de dire que si windows gére le mapping mémoire il peut être mis en défaut sur des problémes de timming (en gros et pour faire simple quand une tache est longue quand elle rend la main windows n'est plus capable d'exécuter celles qui se sont accumulées.
pour le systeme windows c'est Xp pro
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
14 déc. 2005 à 10:32
tiens je viens de verifier :
vus que l'interet apparement est de ne pas augmenter la taille de la close uses :

on extrait PosEx de strutils et on la place dans l'unité principale.

copy, pos et length sont incluse dans l'unité system (qui ne necessite pas qu'on la declare)

donc avec ma methode on obtient certe deux fonctions au lieu d'une (posex et chainepos)
tout en gardant les perf et les avantages de ma version.

alors revoila une version "compressée non lisible" de la fonction (sans avoir a declarer une unité en plus dans les uses) :

function ChainePos(const Sep, Dans: String; const posi: cardinal = 1): String;
function e_PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
var I, X, Len, LenSubStr: Integer;
begin
if Offset = 1 then Result := Pos(SubStr,S) else begin
I := Offset; LenSubStr := Length(SubStr); Len := Length(S)-LenSubStr+1;
while I <Len do begin if S[I] SubStr[1] then begin X := 1;
while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do Inc(X);
if X = LenSubStr then begin Result := I; exit; end;
end; Inc(I); end; Result := 0; end;
end;
var i,p1,p2 : integer;
begin
result :''; if (Dans[1] Sep) and (posi = 1) then exit;
p1 := 1; for i := 1 to posi-1 do begin
p1 :e_posex(sep,dans,p1); if p1 0 then exit else p1 := p1 + length(sep); end;
p2 :e_posex(sep,dans,p1); if p2 0 then p2 := length(Dans)+1;
result := copy(dans,p1,p2-p1);
end;

(je tiens a la vendre cette methode ou quoi ^^ lol)
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
14 déc. 2005 à 09:59
JLen100 >> "sans parler de la stabilité de windows"

Heu ... l'assembleur c'est la base de toute machine, je ne vois pas pourquoi Windows n'accepterais pas trop cela vus que tout programme compiler est forcement retranscrit en assembleur.

puis l'assembleur est relativement bien portable vus qu'on agit directement sur le Proco.
bien entendus, il faudrat tenir compte du type de CPU et du jeux d'instruc supporté par le CPU... le seul probleme qu'il y auras serat sur un portage asmX86 vers Motorola et autre.

pour ce qui est des boucles, forcement si tu fait pas gaffe a la sortie ... que ça soit en n'importe quel langage ça reviendras a faire freezer l'appli ce qui est toujours mauvais.

pour le truc du timer qui attend ... la je dirais, mauvaise methode! il faut utiliser les evenements plutot qu'un timer (bien que je ne connaisse pas réellement le probleme exposé).
mais un timer pour ça je dirais = ressource gachée inutilement.

et puis je vois mal quel dev aurait envie de créer une boucle infinie aucun interet de developper un bugware, windows suffit.

question, sous quel systeme windows est tu ?
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
13 déc. 2005 à 11:13
pas toujours BruNews puisque qu'il n'est arrivé récemment de planter windows sur un while dont j'avais oublié de mettre à jour la condition de sortie: ce n'est pas une simple condition de mapping mais également un problème de timming (il ne faut pas oublier que windows n'est réellement multiltache)
autre exemple: attendre dans un timer une chaine de caractères sur la liaison série rend windows instable.( au mieux ce sont des problèmes d'affichage au pire le plantage)
enfin en assembleur rien de plus facile que de faire un infinit loop sans erreur d'adressage et là windows n'y voit goute!!
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 déc. 2005 à 10:58
Traiter un buffer, que soit une chaine ou autre, en ASM ou quelque autre langage que ce soit n'entamera en rien la stabilité de Windows. Le prog est dans SON propre espace de mémoire virtuelle et se verra démappé illico par le système avec l'injureBox habituelle s'il commet une erreur d'adressage, rien de plus.
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
13 déc. 2005 à 10:47
-->foxi c'est normal que la performance soit dégardé puisqu'à chaque boucle tu as creation et destruction d'une chaine dynamique mais si tu déclares ta chaine comme string[255] ta performance sera meilleure (dans ce cas l'espace est réservé à l'initialisation de la fonction) mais moins bonne que si tu travailles sur les index (nombre d'instructions exécutées superieur)(ou les pointeurs qui est la méthode la plus rapide) mais si l'on veut vraiment aller encore plus vite on peut aussi travailler au niveau de l'assembleur; mais bonjour la portabilité!!! sans parler de la stabilité de windows puisque sur une procédure un peu longue on pertube la gestion des streams.
--> AMEHDOUDALI pour le tuto ça a été un peu laborieux : je ne devrais jamais programmer avant et après une teuf!!
pour l'utilisation des unités il me semblait qu'à la compilation DELPHI n'intégrait que les fonctions et procédures utilisées et que les autres étaient ignorées. (c'est ce que faisait Turbo Pascal)
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
13 déc. 2005 à 10:20
Merci pour la pub Ahmed Boudali!
AhmedBoudali Messages postés 14 Date d'inscription mardi 24 octobre 2000 Statut Membre Dernière intervention 13 décembre 2005
13 déc. 2005 à 10:10
Je conseille un petit tour intéressant du côté du portugal avec les sources de Mauricio.

Jlen100->Je remercie pour l'excellent tuto sur les lecture/ecriture de bits (voir forum).

Foxi->Désolé de ne pas avoir envisagé des fichiers spéciaux comportant des séparateurs à plusieurs caractères (Champ1CeciestseparateuroptimisestandardChamp2Ceciestseparateuroptimisestandard !). Pour ce qui est de copier une fonction d'une unit, celà me semble extrêment intéressant et devrait faire l'objet d'un petit tutoriel de ta part sur les pièges à éviter. Pour ma part, je teste cette éventualité.
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
12 déc. 2005 à 18:33
alors, y'a eu pas mal de post depuis la derniere fois.

@JLen100 : les performances sont fortement degradée a partir du moment ou on utilise ceci :

for x := S to F do string := string + char[x];

constatation generale... no comment. c'est lourd. et le seul moyen de gagner en perf et d'utiliser les pointeurs, ce qui bien sur (et je ne comprend toujours pas pourquoi) n'est pas conseiller avec Dot Net.

@Ahmed : afin de ne pas accroitre les declaration uses (d'ailleur je vois pas ou est le probleme) on peu extraire la fonction Posex() de l'unité StrUtils.

function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
var I, X, Len, LenSubStr: Integer;
begin
if Offset = 1 then Result := Pos(SubStr, S)
else begin
I := Offset;
LenSubStr := Length(SubStr);
Len := Length(S) - LenSubStr + 1;
while I <= Len do begin
if S[I] = SubStr[1] then begin
X := 1;
while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do Inc(X);
if (X = LenSubStr) then begin
Result := I;
exit;
end;
end;
Inc(I);
end;
Result := 0;
end;
end;

Copy et Length sont incluse dans l'unité System qui est presque "obligatoire" la plupart du temps. donc ça ne changeras rien de les extraires de cette derniere.

On oblige a utiliser un nombre positif car il serait illogique de demander des elements en dehors du champs 1..N. tout simplement.

Pour ta fonction, et meme certaines autres propositions, il y a soit un probleme de performance, soit un probleme de souplesse (separateur a caractere unique)...
DelphiProg a bien cerné l'utilisation plus generale de ma fonction. si maintenant cette fonction ne vas servir que dans ce programme pour une utilisation bien precise, voir les autres solutions proposées.

Pour ton soucis d'augmenter les declarations dans la close Uses, tu peut toujours te créer une unité d'alias, cela reviendras au meme mais diminueras la close principale ^^

@Emhandal : les labels sont assé vieux, mais depuis que le pascal n'est plus un langage lineaire ils n'ont plus raisons d'etre. bon ça peut toujours etre utile dans certain cas rare, mais un debutant devrais apprendre a programmer en delphi sans les utiliser.

tiré de l'aide delphi :
L'utilisation de l'instruction goto est généralement déconseillée en programmation structurée. Elle peut néanmoins être utilisée dans certains cas pour sortir de boucles imbriquées.
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 13:18
he oui on ne peut récuperer l'octet 0 que si on déclare la chaine en string[xx] (shortstring)
Emandhal Messages postés 194 Date d'inscription dimanche 2 mars 2003 Statut Membre Dernière intervention 10 octobre 2006 3
11 déc. 2005 à 13:09
bah oui c'est normal, une chaine commence toujours à 1, si tu lui sors un 0 ilne va pas être content...
De plus c'est par octets, le Dans[0] serait valable que dans un ShortString (qui se limite qu'à 255 caractères). Pour les string il faut prendre Dans[-3]..Dans[0] vu que la chaine peut aller jusqu'a High(Integer)...
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 13:04
integer(Dans[0])ne fonctionne pas non sur une varaiable dynamique non initialisée (erreur de compilation élément 0 inaccessible comme pour ord() )
Emandhal Messages postés 194 Date d'inscription dimanche 2 mars 2003 Statut Membre Dernière intervention 10 octobre 2006 3
11 déc. 2005 à 12:55
Integer(Dans[0]) ^^
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 12:19
mille excuses ord() ne fonctionne pas avec les variables dynamiques non affectées.
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 11:57
j'ai oublier fais ord(Dans[0]) pour transtyper le char en integer
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 11:54
pour length() lis le caractere 0 ---> Dans[0]:= longueur de la chaine.
AhmedBoudali Messages postés 14 Date d'inscription mardi 24 octobre 2000 Statut Membre Dernière intervention 13 décembre 2005
11 déc. 2005 à 11:48
Merci JLen100 pour ces remarques.
*J'ai maintenu b pour une lecture aisée

Pour Tout le monde
*Je cherche un moyen d'éviter les fonctions et donc m'approcher d'une version automate(reste length()). Une idée ?

D'avance merci.
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 11:31
pour déterminer la position du premier séparateur tu peux aussi utiliser la fonction pos (unité system) qui te renvoie la positon du premier séparateur trouvé dans la chaine debut=pos(sep,Dans);
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
11 déc. 2005 à 11:21
-->AHMEDBOUDALI
plutot que de faire:
if (b=Sep)then mets plutot if (Dans[i]=Sep)then...
et utilises un index de début et un index de fin et avant de sortir tu fais:
result:= copy(Dans,debut,fin-debut) tu éviteras les réallocations de mémoire.
nota copy et length(que tu utilises) font parties de l'unité system.
AhmedBoudali Messages postés 14 Date d'inscription mardi 24 octobre 2000 Statut Membre Dernière intervention 13 décembre 2005
11 déc. 2005 à 10:47
Mes amis,
Je dois convenir que vos remarques sont empreintes d'une maîtrise que j'espère atteindre.
*La petite histoire de ce code (en dehors de ressusciter le basic) est un pari avec un collègue d'arriver à un automate, avec le moins de lignes (il en a horreur) et à traiter tous les cas de figure possibles sur une ligne d'un fichier texte délimité :
--> Ahmed/Boudali/ ==>si 1 alors Ahmed,si 3 alors vide
--> /Ahmed/Boudali/ ==>si 1 alors vide,si 2 alors Ahmed
--> /Ahmed//Boudali/ ==>si 1 alors vide,si 3 alors vide
--> /Ahmed/Boudali ==>si 1 alors vide,si 4 alors vide

*L'utilisation de length(), posex(), copy() oblige à accroître la liste "Uses".
*Pourquoi forcer l'entrée d'un numéro de position positif (format byte ou word) ?
*Reste la performance et les allocations de mémoire pour string, là mon code pêche... Effectivement, les variables "Sep" et "b" doivent être déclaré en char, la variable "a" doit être remplacé par Result et Result a une longueur maximum équivalent à celle de la valeur entrée ("Dans").

Merci encore pour ces pertinentes remarques.
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
10 déc. 2005 à 19:52
Beau travail les gars et discussions intelligentes.
Ca commençait à nous manquer ces derniers temps, n'est-ce pas foxi ? ;o)

J'attire votre attention tout de même sur le fait que l'usage des pointeurs n'est pas bienvenu sous .Net. Si vous devez porter votre code pour qu'il fonctionne dans cet environnement, vous devrez alors privilégier la solution proposée par foxi.
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
10 déc. 2005 à 18:27
c'est vrai que quelques commentaires auraient été utiles. Mais on voit quand même que tu travailles avec les pointeurs.
deux petites remarques
- la chaine ne doit pas contenir de #0 ( Pchar à 0 terminal)
- la routine de foxi est plus générale ( pas de limitation sur la longueur du séparateur)
mais à part ces détails joli travail!!
@+
jlen
Emandhal Messages postés 194 Date d'inscription dimanche 2 mars 2003 Statut Membre Dernière intervention 10 octobre 2006 3
10 déc. 2005 à 18:17
j'avoue ce dernier post est pas des plus utile... pas d'explications, pas de commentaires... et je m'en excuse :)
Emandhal Messages postés 194 Date d'inscription dimanche 2 mars 2003 Statut Membre Dernière intervention 10 octobre 2006 3
10 déc. 2005 à 18:06
aller, j'aime les défis d'optimisation ^^
ma version delphi :

Function SubString(aStr: String; aSepar: Char; n: Integer): String;
{===============================================================================}
{ renvoie ce qui est à gauche de la droite de la n ieme sous chaine séparée par }
{ aSepar de la chaine aStr }
{ ex : SubString('TMP|c:\rep1\reptmp\', '|', 1) renvoie 'c:\rep1\reptmp\' }
{ Permet d'extraire un à un les éléments d'une chaine séparés par un séparateur }
{===============================================================================}
Var
pStr, pRes, pStart: PChar;
Nb: Integer;
Function PosChr(aString: PChar; aChr: Char): PChar;
Begin
Result := nil;
While aString^<>#0 do
begin
If aString^=aChr Then
begin Result := aString; Exit; end;
Inc(aString);
end;
End;

Begin
Result := '';
If n<0 Then Exit;
aStr := aStr+aSepar;
Nb := 0;
pStr := PChar(aStr);
While pStr^<>#0 do
begin
pRes := PosChr(pStr, aSepar);
If pRes=nil Then Exit;
If Nb=n Then
begin System.SetString(Result, pStr, pRes-pStr); Exit; end;
pStr := pRes+1;
Inc(Nb);
end;
End;

c'est une vieille routine que j'ai adaptée pour gérer uniquement des caractères comme séparateur

f0xi -> tu serais étonné si tu voyais certains de mes codes... j'ai deja mis des goto qui font gagner en rapiditée dans mes codes :)
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
10 déc. 2005 à 07:57
salut foxi,
pour le manque de performance du code je pense (mais je ne l'ai pas tester)que cela viens surtout des affectations des strings (a et b).
je m'explique quand on uilise un string en variable locale c'est toujours une variable dynamique donc a chaque fois qu'une modification de la variable affecte sa longueur le programme travaille comme ça:
appel au gestionnaire de tas pour reserver l'espace mémoire pour la taille de chaine
concatenetion de la chaine initiale et de l'ajout
libération de la mémoire occupée par la chaine initiale
il est donc préférable de considérer la chaine comme un tableau et travailler sur des pointeurs dans ce tableau (ce que fait posex)
c'est aussi pour cela que quand on le peut il vaut mieux affecter une longueur fixe à une chaine par l'utilisation de string[xx] le commpilateur reserve alors un espace mémoire fixe
il en est de même quand on déclare une variable de type scalaire (char, integer, byte......).
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
10 déc. 2005 à 01:36
Lut ami jlen!

alors pour le petit probleme, il n'est pas voulus. c'est en fait posex qui procede de cette maniere.
en effet, d'accord avec toi sur le fait que ce n'est pas trés "delphi".

donc voila un correctif qui ne degrade meme pas les performance de la routine :

function ChainePos(const Sep, Dans: String; const posi: byte = 1): String;
var i,p1,p2 : integer;
begin

result := '';
if (Dans[1] = Sep) and (posi = 1) then begin
exit;
end;

p1 := 1;
for i := 1 to posi-1 do begin
p1 := posex(sep,dans,p1);
// permet de stoper si on vas au dela de la taille de la chaine.
if p1 = 0 then begin
exit;
end
// sinon on continus.
else begin
p1 := p1 + length(sep);
end;
end;

p2 := posex(sep,dans,p1);
if p2 = 0 then p2 := length(Dans)+1;

result := copy(dans,p1,p2-p1);
end;


voila, conforme a l'esprit delphi.
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
9 déc. 2005 à 23:29
-->foxi,
en cas de dépassement il serait plus judicieux de renvoyer une chaine vide (c'est plus conforme à l'esprit DELPHI et à la logique: si on est au dela c'est qu'on a pas trouver l'élément d'autre part si tu retournes le premier terme il y a ambiguité avec la requete du mot 1 ce qui ne facilite pas l'utilisation.
-->AhmedBoudali
plutot que d'utiliser un GOTO antediluvien tu aurais pu écrire:
if (Dans[1]=Sep) and (posi=1) then
begin
Result:=a;
exit;
end;
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
9 déc. 2005 à 23:06
Holala! un bon vieux GOTO! le Basic c'est finis mon ami!

tu peux faire comme cela :

uses strutils; //pour posex

function ChainePos(const Sep, Dans: String; const posi: byte = 1): String;
var i,p1,p2 : integer;
begin
result := '';

// si le premier element n'est pas definis on sort tout de suite
if (Dans[1] = Sep) and (posi = 1) then exit;

// on initialise P1 a 1
p1 := 1;

// on recherche la position du separateur N dans la chaine
for i := 1 to posi-1 do p1 := posex(sep,dans,p1)+length(sep);

// on recherche la position du prochain separateur aprés P1
p2 := posex(sep,dans,p1);
// si on l'a pas trouver c'est qu'on est surrement en fin de chaine
// P2 devient donc la taille de la chaine+1.
if p2 = 0 then p2 := length(Dans)+1;

// on renvois le resultat en utilisant la fonction copy
result := copy(Dans, p1, p2-p1);
end;

Cette methode est beaucoup plus rapide; 68ms de moyenne pour ma methode contre 1900ms de moyenne pour la tienne sur 100000 requettes. Les performances de tes programmes s'en trouverons donc grandement ameliorée.

La supression des variables A et B permettras aussi de gagner en memoire.
d'ailleur dans ta methode, B aurait du etre declarée en Char et non en String.

l'ecriture de "const posi : integer = 1" permet de ne pas definir posi si on desir le premier mot de la chaine. ce qui pourrait etre utile dans certaine utilisation.
d'ailleur sur ce point, posi doit etre de type Byte (0..255) pour eviter les nombre negatif.
cela laisse une large manoeuvre dans le nombres de mots. si Byte est trop restrictif, on peu le declarer en type word (0..65535) ou encore LongWord (0..beaucoup) ce qui augmenteras le nombre de mots possible dans une chaine.
Mais byte me semble tout a fait correct pour cette utilisation.

fonctionnement :

Dans le cas ou Posi est egal a 1 et que le separateur est en position 1 on sort tout de suite de la fonction (exit), vus qu'on a deja assigné '' a result mais copy serat capable de renvoyer un element vide a une autre position.

Dans le cas ou Posi est superieur au nombres de separateurs, ChainePos boucle les elements en repartant de 1.
donc en cas de depassement ChainePos revient au debut et renvois l'element correspondant.
exemple :
chat;chien;lapin;chevre

si on demande le mot 4, chainepos renvois "chevre",
si on demande l'element 5 (qui n'existe pas) chainepos renvois "chat" .
si on demande l'element 8 (qui n'existe pas non plus), chainepos renvois "chevre"

Grace a "posex(sep,dans,p1)+length(sep)" on peut definir des separateurs d'une longueur superieur a 1 caracteres. cela peut egalement etre trés utile si on utilise par exemple un Eoln ou double-Tabulation comme separateur (#13+#10 ou #9+#9).
ou encore, si le separateur est un mot constant lui aussi exemple :
"chienPOUFchatPOUFlapinPOUFcheval"
ici notre separateur serat "POUF"

voila, j'espere que tout cela te serviras.
Rejoignez-nous