Lire une sous-chaine dans une chaine contenant des séparateurs.

Soyez le premier à donner votre avis sur cette source.

Snippet vu 12 773 fois - Téléchargée 30 fois

Contenu du snippet

Soit une chaine contenant des sous-chaines séparées par un caractère. Comment récupérer la xième sous-chaine ?
Voir le code remanié après les contributions.

Source / Exemple :


function ChainePos(const Sep, Dans: String; const posi: cardinal = 1): String;
{fonction revisée par les commentateurs CodeSources comporte
- copie d'une fonction de l'unit sysuts "posex",
- retour d'une sous-chaine tirée d'une chaine selon séparateur et position entrés}

   //Déclaration
   function e_PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
     {renvoi le numero de position d'une chaine Substr dans une chaine S en scannant
     à partir de la position Offset}
     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 if X
              end; //end if S[I]
              Inc(I);
         end;//end while
         Result := 0;
     end; //end else if
   end; //end function

var i,p1,p2 : integer;

begin
//initialisation fonction ChainePos
result := '';

//sortie prématurée avec séparateur en premiere position dans la chaine
if (e_posex(sep,Dans[1] = 1) and (posi <= 1) then exit;

//1ère position de lecture pour la fonction e_posex
p1 := 1;
//Boucle
for i := 1 to posi-1 do
  begin
    //recherche position prochain séparateur pour borne à gauche
    p1 := e_posex(sep,dans,p1);
    if p1 = 0 then
      exit                      //sortie prématurée pas de prochain séparateur
    else
      p1 := p1 + length(sep);   //sinon décale jusqu'à caract<>sep
                                //pour recherche suivante ou sortie
  end;

//Recherche prochain séparateur pour borne à droite...
p2 := e_posex(sep,dans,p1);
//...En cas d'absence, par défaut longueur chaine entrée+1 pour la dernier caractère
if p2 = 0 then
  p2 := length(Dans)+1;

//Fin : extraction sous-chaine de position p1, longueur p2-p1
result := copy(dans,p1,p2-p1);
end;

Conclusion :


La fonction marche si on indique un séparateur de 1 car., une chaine d'au moins 1 car. et si position est supérieur à 0 bien sûr.

A vous de juger...

A voir également

Ajouter un commentaire

Commentaires

kurayamino
Messages postés
3
Date d'inscription
samedi 21 décembre 2002
Statut
Membre
Dernière intervention
18 décembre 2005
-
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
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26 -
@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
1649
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
7 -
-->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
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26 -
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
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26 -
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 ?

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.