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

Langage Delphi Discussion :

Construire un tableau à partir d'une chaine (Spliter)


Sujet :

Langage Delphi

  1. #1
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 264
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 264
    Points : 19 430
    Points
    19 430
    Billets dans le blog
    63
    Par défaut Construire un tableau à partir d'une chaine (Spliter)
    Bonjour à tous !

    Est-il possible de spliter une chaine dans un tableau à partir d'un délimiteur ?

    Merci à tous,

    @+
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  2. #2
    Membre actif
    Profil pro
    DEV
    Inscrit en
    Août 2006
    Messages
    182
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : DEV

    Informations forums :
    Inscription : Août 2006
    Messages : 182
    Points : 211
    Points
    211
    Par défaut
    Salut,
    Oui la fonction recherche du forum est la pour ca
    Recherche Explode ou Split et je pense que tu devrais trouver ton bonheur

    DragonHeart.

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    ExtractStrings de Delphi (Classes.pas)

    Sinon, ICI, tu as un message de moi, qui énumère toutes les variantes disponibles de Explode/Split, et leur performance (à noter que mes fonctions sont basés sur un précalcul de la longueur du tableau sortant, ce qui dans certains cas, peu être plus lent, mais dans une grande majorité, cela dépote un max)

    les Dernières versions étant celles-ci (sur le forum peu y a voir plus de 10 versions buggées ...), donc voici le code :

    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
    {* -----------------------------------------------------------------------------
    la fonction ExplodeLazy retourne un tableau de chaînes. Ce sont les sous-chaînes, extraites de S, en utilisant le séparateur Separator.
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separator Caractère qui délimitent une chaine pour la découpe
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function ExplodeLazy(const S: string; out A: Types.TStringDynArray; Separator: Char): Integer;
    var
      I, J, K: integer;
      iLenS: integer;
    begin
      iLenS := Length(S);
     
      if iLenS = 0 then
      begin
        SetLength(A, 1);
        Result := 0;
        A[Result] := '';
        Exit;
      end;
     
      Result := 0;
      for I := 1 to iLenS do
        if S[I] = Separator then
          Inc(Result);
     
      if S[iLenS] = Separator then
        SetLength(A, Result)
      else
        SetLength(A, Result + 1);
     
      K := 1;
      J := 0;
      for I := 1 to iLenS do
        if S[I] = Separator then
        begin
          if K <> I then
            A[J] := Copy(S, K, I - K);
     
          Inc(J);
          K := I + 1;
        end;
      if K <= iLenS then
        A[J] := Copy(S, K, MaxInt);
    end;
    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
    {* -----------------------------------------------------------------------------
    la fonction ExplodeLazyToStrings encapsule ExplodeLazy pour renvoyer une liste.
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separator Caractère qui délimitent une chaine pour la découpe
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function ExplodeLazyToStrings(const S: string; L: TStrings; Separator: Char; DoClear: Boolean = True): Integer;
    var
      A: Types.TStringDynArray;
      iL: Integer;
    begin
      if Assigned(L) then
      begin
        Result := Explode(S, A, Separator);
        if DoClear then
        begin
          L.Clear();
          L.Capacity := Result;
        end else
          L.Capacity := L.Capacity + Result;
     
        for iL := Low(A) to High(A) do
          L.Add(A[iL]);
      end else
        Result := -1;
    end;
    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    {* -----------------------------------------------------------------------------
    la fonction Explode retourne un tableau de chaînes. Ce sont les sous-chaînes, extraites de S, en utilisant le séparateur Separator. cela peut servir pour lire du CSV
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separators Caractères qui délimitent une chaine pour la découpe
    @param ExcludeEmpty Si True, les Chaines vides ne sont pas insérés dans le Tableau
    @param Quotes Caractères qui délimitent une chaine pour la découpe contenant des Separators, n'importe quel séparateur peut commencer et terminé une chaine, une quote doublée est considéré comme valeur un quote dans la chaine
    @param KeepSeparators Si True, A contient les chaines et les séparateurs mais pas les Quotes, sinon (par défaut) A ne contient que les Chaines.
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function Explode(const S: string; out A: Types.TStringDynArray; const Separators: string; ExcludeEmpty: Boolean = False; const Quotes: string = ''; KeepSeparators: Boolean = False): Integer;
    var
      iLesSep: Integer;
      iLesQuote: Integer;
     
      function IsSeparator(C: Char): Integer;
      begin
        for Result := 1 to iLesSep do
          if C = Separators[Result] then
            Exit;
     
        Result := -1;
      end;
     
      function IsQuote(C: Char): Integer;
      begin
        for Result := 1 to iLesQuote do
          if C = Quotes[Result] then
            Exit;
     
        Result := -1;
      end;
     
    var
      iStr: Integer;
      iQuote: Integer;
      iLenS: Integer;
      iLenSS: Integer;
      iLenA: Integer;
      iAdded: Integer;
      iBegin: Integer;
      Quoted: Boolean;
      DoubleQuoted: Boolean;
      AlreadyDQ: Boolean;
      QuoteConcat: string;
      iOffQuote: Integer;
      LastIsSep: Boolean;
    begin
      iLenS := Length(S);
      iLesSep := Length(Separators);
     
      if (iLenS = 0) or (iLesSep = 0) then
      begin
        SetLength(A, 1);
        Result := 0;
        A[Result] := '';
        Exit;
      end;
     
      iLesQuote := Length(Quotes);
      for iQuote := 1 to iLesQuote do
        if IsSeparator(Quotes[iQuote]) > 0 then
          raise EParserError.CreateFmt('le Délimiteur "%s" ne peut pas être un Séparateur !', [Quotes[iQuote]]);
     
      Result := 0;
      iQuote := 0;
      for iStr := 1 to Length(S) do
      begin
        if IsSeparator(S[iStr]) > 0 then
          Inc(Result)
        else
          if IsQuote(S[iStr]) > 0 then
            Inc(iQuote);
      end;
     
      if Odd(iQuote) then
        raise EParserError.CreateFmt('Nombre de Délimiteur Incorrect : "%d" !', [iQuote]);
     
      LastIsSep := IsSeparator(S[iLenS]) > 0;
     
      if KeepSeparators then
        iLenA := Result * 2 + 1
      else
        iLenA := Result + 1;
      SetLength(A, iLenA);
      iLenSS := 0;
      iAdded := 0;
      Quoted := False;
      iOffQuote := 0;
      QuoteConcat := '';
      AlreadyDQ := False;
      iBegin := 1;
      if IsSeparator(S[1]) > 0 then
      begin
        if KeepSeparators then
        begin
          iBegin := 2;
          A[iAdded] := S[1];
          Inc(iAdded);
        end;
      end;
     
      for iStr := iBegin to iLenS do
      begin
        if not Quoted and (IsSeparator(S[iStr]) > 0) then
        begin
          if ExcludeEmpty and (iLenSS = 0) then
          begin
            if KeepSeparators then
            begin
              A[iAdded] := S[iStr];
              Inc(iAdded);
            end;
            iBegin := iStr + 1;
          end else
          begin
            if AlreadyDQ then
              A[iAdded] := QuoteConcat
            else
              A[iAdded] := Copy(S, iBegin, iLenSS);
     
            AlreadyDQ := False;
            Inc(iAdded);
     
            if KeepSeparators and (iBegin > 0) then
            begin
              A[iAdded] := S[iStr];
              Inc(iAdded);
            end else
              begin
              if LastIsSep and KeepSeparators and (iStr = iLenS) then
              begin
                A[iAdded] := S[iStr];
                Inc(iAdded);
              end;
            end;
            iBegin := iStr + 1;
            iLenSS := 0;
          end;
        end else
        begin
          if IsQuote(S[iStr]) > 0 then
          begin
            if Quoted then
            begin
              Quoted := False;
              if iStr < iLenS then
              begin
                DoubleQuoted := IsQuote(S[iStr+1]) > 0;
                if AlreadyDQ then
                  QuoteConcat := QuoteConcat + Copy(S, iBegin, iLenSS) + IfThen(DoubleQuoted, S[iStr+1], '')
                else
                  QuoteConcat := Copy(S, iBegin, iLenSS) + IfThen(DoubleQuoted, S[iStr+1], '');
                AlreadyDQ := AlreadyDQ or DoubleQuoted;
              end;
            end else
            begin
              Quoted := True;
              iBegin := iStr + 1;
              iLenSS := 0;
            end;
          end else
          begin
            if Quoted and (IsSeparator(S[iStr]) > 0) then
              Inc(iOffQuote);
            Inc(iLenSS);
          end;
        end;
      end;
     
      if iBegin <= iLenS then
      begin
        A[iAdded] := Copy(S, iBegin, MaxInt);
        Inc(iAdded);
     
        if LastIsSep and KeepSeparators then
        begin
          A[iAdded] := S[iLenS];
          Inc(iAdded);
        end;
      end;
     
      if LastIsSep and not ExcludeEmpty then
        Inc(iAdded);
     
      if iAdded < iLenA then
        A := Copy(A, 0, iAdded);
     
      Result := Result - iOffQuote;
    end;
    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
    {* -----------------------------------------------------------------------------
    la fonction ExplodeToStrings encapsule Explode pour renvoyer une liste.
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separators Caractères qui délimitent une chaine pour la découpe
    @param ExcludeEmpty Si True, les Chaines vides ne sont pas insérés dans le Tableau
    @param Quotes Caractères qui délimitent une chaine pour la découpe contenant des Separators
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function ExplodeToStrings(const S: string; L: TStrings; const Separators: string; ExcludeEmpty: Boolean = False; const Quotes: string = ''): Integer;
    var
      A: Types.TStringDynArray;
      iL: Integer;
    begin
      if Assigned(L) then
      begin
        Result := Explode(S, A, Separators, ExcludeEmpty, Quotes);
        L.Clear();
        L.Capacity := Result;
        for iL := Low(A) to High(A) do
          L.Add(A[iL]);
      end else
        Result := -1;
    end;
    Pour l'esprit sportif, il y a aussi la PCHAR, pas de grande différence de perf, je n'ai fait que la Lazy, faut être honnête, la explode complète en PChar ne fonctionne pas ^_^ violation d'accès ...

    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
    {* -----------------------------------------------------------------------------
    la fonction ExplodeLazyPChar retourne un tableau de chaînes. Ce sont les sous-chaînes, extraites de S, en utilisant le séparateur Separator.
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separator Caractère qui délimitent une chaine pour la découpe
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function ExplodeLazyPChar(const S: string; out A: Types.TStringDynArray; Separator: Char): Integer;
    var
      J, K, L: integer;
      P, P2, PEnd: PChar;
    begin
      Result := 0;
      L := Length(S);
      P := Pointer(S);
      P2 := P;
      PEnd := P;
      Inc(PEnd, L);
     
      while P < PEnd do
      begin
        if P^ = Separator then
        begin
          Inc(Result);
        end;
        Inc(P);
      end;
     
      if S[L] = Separator then
        SetLength(A, Result)
      else
        SetLength(A, Result + 1);
     
      K := 0;
      J := 0;
      P := P2;
      while P < PEnd do
      begin
        if P^ = Separator then
        begin
          if K > 0 then
          begin
            SetLength(A[J], K);
            Move(P2^, PChar(A[J])^, K);
            K := 0;
          end;
          P2 := P;
          Inc(P2);
          Inc(J);
        end else
        begin
          Inc(K);
        end;
     
        Inc(P);
      end;
     
      if (P2 < PEnd) and (K > 0) then
      begin
        SetLength(A[J], K);
        Move(P2^, PChar(A[J])^, K);
      end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 264
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 264
    Points : 19 430
    Points
    19 430
    Billets dans le blog
    63
    Par défaut
    Merci ShaiLeTroll,
    merci à tous,
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Bon, je remonte ce sujet, pour communiquer une nouvelle version de Explode pour gérer le cas suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "00000001";"00000002";"00000003"  ;"00000004";"00000005";"00000006";"00000007";"00000008";"00000009";"00000010";"00000011";"00000012"
    ce qui est contenu entre la 6eme " et le 3eme ; est ignorée

    Qu'en pensez-vous ?
    Merci de me communiquer d'éventuels bugs

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    {* -----------------------------------------------------------------------------
    la fonction Explode retourne un tableau de chaînes. Ce sont les sous-chaînes, extraites de S, en utilisant le séparateur Separator. cela peut servir pour lire du CSV
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separators Caractères qui délimitent une chaine pour la découpe
    @param ExcludeEmpty Si True, les Chaines vides ne sont pas insérés dans le Tableau
    @param Quotes Caractères qui délimitent une chaine pour la découpe contenant des Separators, n'importe quel séparateur peut commencer et terminé une chaine, une quote doublée est considéré comme valeur un quote dans la chaine
    @param KeepSeparators Si True, A contient les chaines et les séparateurs mais pas les Quotes, sinon (par défaut) A ne contient que les Chaines.
    @param KeepTextAfterQuote Si True, le Texte entre une quote terminale d'un texte et un séparateur est conservée, la Quote comprise, sinon (par défaut) le Texte entre une quote terminale d'un texte et un séparateur est ignorées
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function Explode(const S: string; out A: Types.TStringDynArray; const Separators: string; ExcludeEmpty: Boolean = False; const Quotes: string = ''; KeepSeparators: Boolean = False; KeepTextAfterQuote: Boolean = False): Integer;
    var
      iLesSep: Integer;
      iLesQuote: Integer;
     
      function IsSeparator(C: Char): Integer;
      begin
        for Result := 1 to iLesSep do
          if C = Separators[Result] then
            Exit;
     
        Result := -1;
      end;
     
      function IsQuote(C: Char): Integer;
      begin
        for Result := 1 to iLesQuote do
          if C = Quotes[Result] then
            Exit;
     
        Result := -1;
      end;
     
    var
      iStr: Integer;
      iQuote: Integer;
      iLenS: Integer;
      iLenSS: Integer;
      iLenA: Integer;
      iAdded: Integer;
      iBegin: Integer;
      Quoted: Boolean;
      DoubleQuoted: Boolean;
      AlreadyDQ: Boolean;
      QuoteConcat: string;
      iOffQuote: Integer;
      LastIsSep: Boolean;
      LastIsQ: Boolean;
      ContinueToNextSeparator: Boolean;
    begin
      iLenS := Length(S);
      iLesSep := Length(Separators);
     
      if (iLenS = 0) or (iLesSep = 0) then
      begin
        SetLength(A, 1);
        Result := 0;
        A[Result] := '';
        Exit;
      end;
     
      iLesQuote := Length(Quotes);
      for iQuote := 1 to iLesQuote do
        if IsSeparator(Quotes[iQuote]) > 0 then
          raise EParserError.CreateFmt('le Délimiteur "%s" ne peut pas être un Séparateur !', [Quotes[iQuote]]);
     
      Result := 0;
      iQuote := 0;
      for iStr := 1 to Length(S) do
      begin
        if IsSeparator(S[iStr]) > 0 then
          Inc(Result)
        else
          if IsQuote(S[iStr]) > 0 then
            Inc(iQuote);
      end;
     
      if Odd(iQuote) then
        raise EParserError.CreateFmt('Nombre de Délimiteur Incorrect : "%d" !', [iQuote]);
     
      LastIsSep := IsSeparator(S[iLenS]) > 0;
      LastIsQ := IsQuote(S[iLenS]) > 0;
     
      if KeepSeparators then
        iLenA := Result * 2 + 1
      else
        iLenA := Result + 1;
      SetLength(A, iLenA);
      iLenSS := 0;
      iAdded := 0;
      Quoted := False;
      iOffQuote := 0;
      QuoteConcat := '';
      AlreadyDQ := False;
      iBegin := 1;
      if IsSeparator(S[1]) > 0 then
      begin
        if KeepSeparators then
        begin
          iBegin := 2;
          A[iAdded] := S[1];
          Inc(iAdded);
        end;
      end;
     
      ContinueToNextSeparator := False;
      for iStr := iBegin to iLenS do
      begin
        if ContinueToNextSeparator and (IsSeparator(S[iStr]) <= 0) then
          Continue;
        ContinueToNextSeparator := False;
     
        if not Quoted and (IsSeparator(S[iStr]) > 0) then
        begin
          if ExcludeEmpty and (iLenSS = 0) then
          begin
            if KeepSeparators then
            begin
              A[iAdded] := S[iStr];
              Inc(iAdded);
            end;
            iBegin := iStr + 1;
          end else
          begin
            if AlreadyDQ then
              A[iAdded] := QuoteConcat
            else
              A[iAdded] := Copy(S, iBegin, iLenSS);
     
            AlreadyDQ := False;
            Inc(iAdded);
     
            if KeepSeparators and (iBegin > 0) then
            begin
              A[iAdded] := S[iStr];
              Inc(iAdded);
            end else
              begin
              if LastIsSep and KeepSeparators and (iStr = iLenS) then
              begin
                A[iAdded] := S[iStr];
                Inc(iAdded);
              end;
            end;
            iBegin := iStr + 1;
            iLenSS := 0;
          end;
        end else
        begin
          if IsQuote(S[iStr]) > 0 then
          begin
            if Quoted then
            begin
              Quoted := False;
              if iStr < iLenS then
              begin
                DoubleQuoted := IsQuote(S[iStr+1]) > 0;
                if not KeepTextAfterQuote and not DoubleQuoted and (IsSeparator(S[iStr+1]) <= 0) then
                begin
                  ContinueToNextSeparator := True;
                  iQuote := iStr;
                end;
                if AlreadyDQ then
                  QuoteConcat := QuoteConcat + Copy(S, iBegin, iLenSS) + IfThen(DoubleQuoted, S[iStr+1], '')
                else
                  QuoteConcat := Copy(S, iBegin, iLenSS) + IfThen(DoubleQuoted, S[iStr+1], '');
                AlreadyDQ := AlreadyDQ or DoubleQuoted;
              end;
            end else
            begin
              Quoted := True;
              iBegin := iStr + 1;
              iLenSS := 0;
            end;
          end else
          begin
            if Quoted and (IsSeparator(S[iStr]) > 0) then
              Inc(iOffQuote);
            Inc(iLenSS);
          end;
        end;
      end;
     
      if iBegin <= iLenS then
      begin
        if ContinueToNextSeparator then
          A[iAdded] := Copy(S, iBegin, iQuote - iBegin)
        else
          if LastIsQ then
            A[iAdded] := Copy(S, iBegin, iLenS - iBegin)
          else
            A[iAdded] := Copy(S, iBegin, MaxInt);
        Inc(iAdded);
     
        if LastIsSep and KeepSeparators then
        begin
          A[iAdded] := S[iLenS];
          Inc(iAdded);
        end;
      end;
     
      if LastIsSep and not ExcludeEmpty then
        Inc(iAdded);
     
      if iAdded < iLenA then
        A := Copy(A, 0, iAdded);
     
      Result := Result - iOffQuote;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Normalement de quoi gagner un pouième de seconde sur les chaînes un peu plus longues:

    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
    function ExplodeLazy(const S: string; out A: Types.TStringDynArray; Separator: Char): Integer;
    var
      I, J, K: Integer;
      iLenS: Integer;
    begin
      Result := 0;
      iLenS := Length(S);
     
      if iLenS = 0 then begin
        SetLength(A, 1);
        A[0] := '';
        Exit;
      end;
     
      SetLength(A, iLenS);
     
      K := 1;
      J := 0;
      for I := 1 to iLenS do
        if S[I] = Separator then begin
          if K <> I then
            A[J] := Copy(S, K, I - K);
     
          Inc(J);
          K := I + 1;
        end;
      if K <= iLenS then
        A[J] := Copy(S, K, MaxInt);
     
      Result := J - 1;
      SetLength(A, Result);
    end;

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    GoustiFruit, tu nous déterre un sujet !

    Tu as retiré le pré-calcul de la longueur !
    Tu n'as pas tord, en fait mon code est optimisé pour D6 !
    Cette technique prédictive est obsolète !

    Dès que l'on utilise FastMM (ou dès D2007, je crois), le SetLength est environ 100 à 1000 fois plus rapide pour la ré-allocation d'un tableau que le Gestionnaire Mémoire de D6 !

    Par contre, si tu as une chaine Longue, tu vas donc utiliser la taille de la chaine pour allouer A un tableau de chaine !
    Donc, pour une chaine longue, disons plus de 1Ko, tu vas allouer inutilement un tableau de 1000 éléments
    Une chaine est un pointeur sur une structure
    Donc ton tableau, devrait faire 4Ko en 32Bits et 8Ko en 64Bits !
    Dans le genre consommation mémoire inutile, c'est un chef-d’œuvre !
    Et mon exemple n'est qu'un 1Ko, pour une chaine de 1Mo ça passe à 4Mo et 8Mo de consommation superflue pour un pauvre Explode !
    Fausse bonne idée !

    A la limite, en FastMM il est préférable de ré-allouer le tableau, cela sera plus rapide que la prédiction !
    On peut aussi allouer par tas de 16, en utilisant une TStringList à la place d'un Array of string, cela est géré nativement via sa méthode interne Grow !

    J'ignore comme fonctionne exactement la fonction _Initialize pour un array of string, je pense qu'elle économise la mémoire en affectant nil comme pointeur de chaine qui simule une chaine vide, d'où juste 4 ou 8 octet par cellule du tableau !

    Heureusement car rappelons qu'une chaine sans même compter les caractères consomment de la mémoire
    D7 = 12 octet, pour le compteur de référence, la longueur et le pointeur lui même
    DXE2 = 15 octet (je crois), le code page, la longueur du char, le compteur de référence, la longueur et le pointeur lui même

    Heureusement que _Initialize n'alloue pas une chaine pour chaque cellule, ça sera effectivement idiot car dans le cas contraire, la consommation mémoire pour une chaine de 1Ko passerait à 8Ko pour chaine Unicode et 15Ko pour une chaine Ansi (taille divisé par deux pour le nombre de char), et ça monterait à 10Ko et 19Ko pour du 64Bits !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    J'ai autre chose dans les tuyaux, je fais quelques vérifications et je poste ;-)

    Petite remarque en passant: pour moi un séparateur est sensé... *séparer*, et oui !, 2 valeurs donc dans les cas suivants:

    - '' (chaine vide) -> la fonction doit retourner 0 pour nombre de séparateurs, et une chaîne vide dans le tableau.
    - ';' -> la fonction doit retourner 1 pour le nombre de séparateurs et 2 chaînes vides dans le tableau !
    - 'A;B -> la fonction doit retourner 1 pour le nombre de séparateurs et les 2 chaînes 'A' et 'B' dans le tableau
    - 'A;B;' -> la fonction doit retourner 2 pour le nombre de séparateurs et les 3 chaînes 'A' et 'B' et '' (vide) dans le tableau
    - etc.

    Ce que je veux dire c'est qu'un séparateur en fin de ligne devrait logiquement indiquer qu'il reste une valeur vide en fin de chaîne ! Si ce n''est pas le cas, c'est que le fichier d'origine a été mal formaté.

    PS: la fonction est sensée être la plus rapide possible, on n'a jamais parlé de l'utilisation mémoire

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ce n'est pas forcément du CSV !

    Sinon une ligne CSV fini forcément par un ; !
    Ce qui est après le dernier ; est du commentaire et non de la donnée, c'est une convention très mal respectée !

    Pour le Result, oui strictement le nombre de séparateur et le nombre de case !
    C'était aussi ma vision des choses !
    Le cas de ';', je n'y avais jamais pensé, ça doit donner 1 et 1 !
    Rappelons que c'est ExplodeLazy !
    La version gérant les valeurs vides, les répétitions de séparateurs ... c'est Explode tout court !

    Version pour FastMM

    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
    {* -----------------------------------------------------------------------------
    la fonction ExplodeLazy retourne un tableau de chaînes. Ce sont les sous-chaînes, extraites de S, en utilisant le séparateur Separator.
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separator Caractère qui délimitent une chaine pour la découpe
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function ExplodeLazy(const S: string; out A: Types.TStringDynArray; Separator: Char): Integer;
    var
      I, J, K: integer;
      iLenS, iLenA: integer;
    begin
      iLenS := Length(S);
     
      if iLenS = 0 then
      begin
        SetLength(A, 1);
        Result := 0;
        A[Result] := '';
        Exit;
      end;
     
      iLenA := 16;
      SetLength(A, iLenA);
     
      K := 1;
      Result := 0;
      for I := 1 to iLenS do
      begin
        if S[I] = Separator then
        begin
          if Result >= iLenA then
          begin   
            iLenA := J + 16;
            SetLength(A, iLenA);
          end;
     
          if K <> I then
            A[Result] := Copy(S, K, I - K);
     
          Inc(Result);
          K := I + 1;
        end;
      end;
     
      J := Result;  
      if K <= iLenS then
      begin
        if J >= iLenA then
        begin   
          iLenA := J + 1;
          SetLength(A, iLenA);
        end;
     
        A[J] := Copy(S, K, MaxInt);
        Inc(J);
      end;
     
      if J < iLenA then
        SetLength(A, J);
    end;
    Citation Envoyé par GoustiFruit Voir le message
    PS: la fonction est sensée être la plus rapide possible, on n'a jamais parlé de l'utilisation mémoire
    Faudrait justement vérifié, allouer la mémoire, cela prend du temps, mettre à nil toute cette mémoire aussi !
    Je pense qu'au final, cela peut se montrer coûteux en temps !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Ce qui me chagrine dans ton code c'est que tu parcours deux fois la chaîne; or quand on fait le découpage mentalement ou sur sa feuille de papier, d'instinct on ne parcourt qu'une seule fois cette chaîne... Alors j'ai pensé à ça:

    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
    function ExplodeLazy(const S: string; out A: TStringDynArray; Separator: Char): Integer;
    var
      aSepPos: TIntegerDynArray;
      i1, iStart, iEnd,
      iLenS: Integer;
    begin
      Result := 0;
      iLenS := Length(S);
     
      SetLength(aSepPos, iLenS);
      for i1 := 1 to iLenS do begin
        if S[i1] = Separator then begin
          aSepPos[Result] := i1;
          Inc(Result);
        end;
      end;
     
      SetLength(A, Result + 1);
      iStart := 1;
      for i1 := 0 to Result - 1 do begin
        iEnd := aSepPos[i1];
        if iEnd > iStart then
          A[i1] := Copy(S, iStart, iEnd - iStart);
        iStart := iEnd + 1;
      end;
      A[Result] := Copy(S, iStart, MaxInt);
    end;
    A modifier légèrement, donc, si on considère que le dernier séparateur ne sépare... rien.

    PS: un tableau d'entiers ça consomme moins qu'un tableau de chaînes non ? ;-)

    GoustiFruit, tu nous déterre un sujet !
    Oui, je sais, mais on revient toujours aux fondamentaux, et hier je cherchais une fonction pour découper une url en ses sous-segments, et de fil en aiguille, ...

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ce qui te chagrine mais justement tout l'originalité de ces fonctionnalités conçus pour D4 à D7, je l'ai d'ailleurs mentionné depuis le début !

    Citation Envoyé par ShaiLeTroll Voir le message
    à noter que mes fonctions sont basés sur un précalcul de la longueur du tableau sortant, ce qui dans certains cas, peu être plus lent, mais dans une grande majorité, cela dépote un max)
    Comme je l'ai dit c'était une "technique prédictive", car parcourir deux fois était plus rapide que de réallouer !
    Ce n'est plus vrai avec FastMM et je l'avais déjà fait remarquer dans le sujet : Création d'objets "par lots" ou dans Temps pour parser un fichier de + de 3 millions de lignes
    Citation Envoyé par ShaiLeTroll Voir le message
    le gestion de mémoire ayant changé, FastMM, les réallocations mémoires sont nettement moins douloureuse qu'avant ... du coup beaucoup de mes algos pré-calculant les longueurs, ne sont plus valables en terme, de performance, encore une chose à améliorer avec D2009)
    Citation Envoyé par ShaiLeTroll Voir le message
    attention, le code est optimisé pour D7, pour les Delphi incluant FastMM en natif, le pré-calcul de l'allocation n'est pas pertinent)
    Si tu lit mon nouveau code, je fais une ré-allocation par bloc !

    Que vient faire là un Tableau d'entier, normalement, un tableau de chaine vide, consomme la même chose qu'un tableau d'entier, évidement en 32bits !
    Dès que tu commence à allouer des chaines, le tableau lui consomme toujours QUE les pointeurs, ensuite c'est les chaines qui consomment par leur Structure en @ négative puis les données

    Ne pas confondre le tableau qui ne stocke que les pointeurs, et la mémoire consommée par les pointeurs eux-même !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Ah tu n'as pas vu, en fait j'ai un peu changé la méthode, le tableau d'entier sert à stocker la position des séparateurs, ensuite on parcourt uniquement ce tableau pour découper la chaîne d'indice en indice.

    Pourrais-tu me pointer vers le message où tu donnes ta technique pour chronométrer cette fonction, mon chronométrage donne un peu trop de fluctuations, je fias un simple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var
      t1, t2: Int64;
      StrArray: TStringDynArray;
      s: string;
      i1: Integer;
    begin
      s := '0;;1;2!2;333;44!44;55555;666!666;7777777;8888!8888;999999999;00000!00000;"AAA";"BBB";"CCC"';
      t1 := DSiTimeGetTime64;
     
      for i1 := 0 to 99999 do
        ExplodeLazy(s, StrArray, ';');
     
      t2 := DSiTimeGetTime64;
      AddToLog(Format('100000 x ExplodeLazy exécuté en %d ms', [t2-t1]));

  13. #13
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ah oui, bonne idée, c'est ce que j'utilise dans SearchString InFile et SearchBinaryInFile

    Mémoriser les offsets pour ensuite pouvoir y retourner !

    Mais en terme de consommation, cela ne doit pas changer grand chose !
    Tu consomme toujours un tableau de 4 fois la taille chaine !

    Fait donc des mesures avec QueryPerformance Counter\Frequency
    Compare les Trois !
    La version SetLength de A
    La version SetLength de aSepPos
    La version SetLength + 16 que j'ai proposé (mais pas du tout testé, ce n'est pas exempte de coquille)

    EDIT : Lol, je n'avais même pas vu ta demande pour le chrono, je le l'ai ajouté de moi même ! On pense pareil !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  14. #14
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Mouais, ta méthode de mesure me donne les mêmes fluctuations :-\
    Un meilleur test serait de vérifier sur un jeu de chaînes très différentes et suffisamment nombreuses...

    Citation Envoyé par ShaiLeTroll Voir le message
    La version SetLength + 16 que j'ai proposé (mais pas du tout testé, ce n'est pas exempte de coquille)
    Oups, en effet coquillette en vue. Violation d'accès sur un "Inc(Result)", je vais enquêter...

    Edit: à vue de nez, remplacer...
    iLenA := J + 16;
    par
    Inc(iLenA, 16);
    ???

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    tu peux remplacer par iLenA := Result + 16; ou par Inc(iLenA, 16);.

    On peut même raccourcir en ceci, on gagne une allocation en cas de chaine ne contenant pas de séparateur

    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
    {* -----------------------------------------------------------------------------
    la fonction ExplodeLazy retourne un tableau de chaînes. Ce sont les sous-chaînes, extraites de S, en utilisant le séparateur Separator.
    @param S Chaine à découper
    @param A Tableau de Chaine qui recevra la découpe
    @param Separator Caractère qui délimitent une chaine pour la découpe
    @return Nombre de Séparateur Trouvé (peut-être différent du nombre de chaine dans A !)
    ------------------------------------------------------------------------------ }
    function ExplodeLazy(const S: string; out A: Types.TStringDynArray; Separator: Char): Integer;
    var
      I, J, K: integer;
      iLenS, iLenA: integer;
    begin
      iLenS := Length(S);
     
      if iLenS = 0 then
      begin
        SetLength(A, 1);
        Result := 0;
        A[Result] := '';
        Exit;
      end;
     
      K := 1;
      Result := 0;
      iLenA := 0;
      for I := 1 to iLenS do
      begin
        if S[I] = Separator then
        begin
          if Result >= iLenA then
          begin   
            iLenA := Result + 16;
            SetLength(A, iLenA);
          end;
     
          if K <> I then
            A[Result] := Copy(S, K, I - K);
     
          Inc(Result);
          K := I + 1;
        end;
      end;
     
      J := Result;  
      if K <= iLenS then
      begin
        if J >= iLenA then
        begin   
          iLenA := J + 1;
          SetLength(A, iLenA);
        end;
     
        A[J] := Copy(S, K, MaxInt);
        Inc(J);
      end;
     
      if J < iLenA then
        SetLength(A, J);
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  16. #16
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Bah chez moi les temps d'exécution varient du simple au double pour chacune des 3 versions, en gros de 110ms à 220ms pour 100000 itérations. Impossible dans ces conditions de déterminer un vainqueur.
    Merci d'avoir passé ta matinée là-dessus

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Construire des tableaux a partir d'une chaine avec les RegExp?
    Par Zineb1987_UNI dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 28/10/2009, 15h10
  2. Réponses: 1
    Dernier message: 28/12/2007, 10h32
  3. Réponses: 7
    Dernier message: 15/11/2005, 10h14
  4. [HTML] construire un mailto à partir d'une table
    Par Kafi dans le forum Balisage (X)HTML et validation W3C
    Réponses: 4
    Dernier message: 08/09/2005, 16h01
  5. [Struts]Ecrire un html:link à partir d'une chaine
    Par cowa dans le forum Struts 1
    Réponses: 5
    Dernier message: 12/05/2004, 17h10

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