Tableaux de chaines de caractère: fonctions implode, explode et count

Soyez le premier à donner votre avis sur cette source.

Snippet vu 15 231 fois - Téléchargée 18 fois

Contenu du snippet

Voici quelques fonctions utiles pour la gestion des tableaux de chaines de caractères (comme les fonctions de PHP).

explode :
scinde une chaine à partir de son délimiteur et retourne 1 tableau de chaines découpées.version php

implode :
fait l'inverse d'explode et fusionne les chaines d'un tableau en une seule chaine.
=>le paramétre optionnel n permet la fusion des n 1ers elts du tableau.

count :
retourne le nombre d'élements d'un tableau de chaines.

int countfields(char delim,char token,char* src):
retour du nombre de champs avec token d'une chaine à spliter
      • AUTRE VERSION d'Explode que j'ai un peu plus optimisée:***


int fieldsExplode(char delim,char token,char * src, char** dest)
=>Fonction ajoutée : Gére les champs entourés par guillemets , quotes ou caractere au choix)

Source / Exemple :


#include <iostream>
using namespace std;

int count(char** tabsrc)
{
    int i=0;
    while (tabsrc[i]!=NULL){i++;}
    return i;
}

char** explode( const char delim, char* src)
{
    char* start = src;
    char* ptr = src;
    char** tab;
    int i = 0, pos = 0, len = 0;
    int items = 0;
    
    //items :calcul nombre d'elements du tableau (nb delimiteurs)
    while ( *src ) { if ( *src == delim ){ items++; } src++; }
    
    //si aucun déilimiteurs pas la peine de se fatiguer
    if ( !items ) return NULL;

    //nombre element= nombre de caractere delim + 1
    items++;

    //réinit du pointeur src
    src = start;

    //allocation memoire du tableau
    tab = new char* [items] ;

    //parcours de la chaine à spliter
    while ( *ptr && i < items )
    {
        if ( *src == delim || *src == 0 )
        {
            len = 0;
            ptr = start;
            while ( ptr < src ){ len++; ptr++; }
            tab[i] = new char [len+1];
            pos = 0;
            while ( start < ptr ){ tab[i][pos] = *start; start++; pos++; }
            tab[i][pos] = 0;
            start = ptr + 1;
            i++;
        }
        src++;
    }
    //fin du tableau
    tab[i]=NULL;
    return tab;
}

char * implode(const char delim, char** tabstring, int n=0)
{
    int i = 0,size = 0, max = count(tabstring);

    char * tmp,*ptr,*start;

    if (n <= 0 || n > max)
        n = max;
    
    // calcul de la taille de la chaine (size) à allouer
    while (i < n)
    {
        ptr = tabstring[i];
        while (*ptr)
        {
            ptr++;
            size++;
        }
        i++;
    }

    // Allocation de la mémoire nécessaire à la chaine à fusionner
    tmp = new char[size+1];
    start = tmp;
    i = 0;

    //fusion
    while (i < n)
    {
       ptr=tabstring[i];
        while (*ptr)
        {

  • tmp = *ptr;
ptr++; tmp++; } if (i < n-1)
  • tmp = delim;
else *tmp = 0; tmp++; i++; } //retour de la chaine fusionnée return start; } int countfields(char delim,char token,char* src) { int i=0,cntL=0; while (*src) { if (*src==delim) { if ( cntL%2!=1 ) { i++; } } if (*src==token) cntL++; src++; } return i+1; } int maxFieldSize(char delim,char token,char* src) { int i=0,a=0,max=0,cntL=0; while (*src) { if (*src==delim) { if ( cntL%2!=1 ) { i++; if (a>max) max=a; a=0; } } if (*src==token) cntL++; src++; a++; } return max; } //la meilleure version d'explode int fieldsExplode(char delim,char token,char * src, char** dest) { char* ptr; int i=0,cntL=0;//,cntR; ptr=dest[0]; while (*src) { if (*src!=delim) { if (*src==token) cntL++;
  • ptr=*src;
ptr++; src++; if (!*src) *ptr=0; } else { //si impaire à gauche on continue if ( cntL%2==1 ) {
  • ptr=*src;
ptr++; } else {
  • ptr=0;
i++; ptr=dest[i]; } src++; } } dest[i+1]=NULL; return i+1; } // pour tester int main () { int items=0; char** explodeTest=explode(';',"voici;;un;test;d;explode"); items=count(explodeTest); for (int i=0;i<items;i++) cout<<"Item "<<i<<": "<<explodeTest[i]<<endl; cout <<"Count():"<<items<<endl; char* implodeTest=implode(';',explodeTest); cout<<"IMPLODE: "<<implodeTest<<endl; return 0; } //exemple avec le nouvel explode int main () { char** tableau; char chaine[200]; int len; strcpy(chaine,"test;'1;2;3';;explode;;'token';2;test"); tableau=new char* [countfields(';','\'',chaine)]; for(int i=0 ; i<10;i++) tableau[i]=new char[maxFieldSize(';','\'',chaine)+1]; len=fieldsExplode(';','\'',chaine,tableau); for(int i=0 ; i<len;i++) cout<<tableau[i]<<endl; }

Conclusion :


Voilà j'ai vu plusieurs fonctions dans ce style pour le split/explode sur ce site,
celle là est un peu différente. Mais sauf erreur de ma part, je n'ai rien vu sur implode ou join.

A voir également

Ajouter un commentaire

Commentaires

BruNews
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
13 -
if(strarr!=NULL && strarr[0]!=NULL)
Si strarr vaut 0, c'est badaboum garanti d'essayer de lire strarr[0].
ranzia
Messages postés
2
Date d'inscription
mardi 22 novembre 2005
Statut
Membre
Dernière intervention
19 décembre 2008
-
Merci pour ce source très utile.
Voici une autre version de la fonction implode() où le délimiteur est une chaine au lieu d'un char.

/**
* Rassemble les elements d'un tableau en une chaine en les concatenant avec le separateur
* @param strarr tableau de chaine
* @param separator separateur (peut etre une chaine vide)
* @return chaine concatenee ou NULL en cas d'erreur
*/

char * implode(const char **strarr, const char *separator)
{
char *res;
int taille_strarr,taille_sep;
int i;
const char *sep;

if(strarr!=NULL && strarr[0]!=NULL)
{
taille_strarr = sizeof(strarr);
res = (char *)malloc((strlen(strarr[0])+1)*sizeof(char));
sprintf(res,"%s",strarr[0]);
if(separator==NULL)
sep = "";
else
sep = separator;
taille_sep = strlen(sep);
for(i=1;i<taille_strarr;i++)
{
res = (char *)realloc(res,(strlen(res)+taille_sep+strlen(strarr[i])+1)*sizeof(char));
sprintf(res,"%s%s%s",res,separator,strarr[i]);
}
return res;
}
return NULL;
}
jacqhal
Messages postés
1
Date d'inscription
vendredi 11 avril 2003
Statut
Membre
Dernière intervention
23 février 2008
-
par contre quelques traitements d'erreur serait certanement bien venu en cas de dépassement de memoire ..

par ex : voici ce que j'ai fait en reprenant une partie de ce que tu avais fait..

int Explode(char* Txt, char**& return_value, char Separator /*= ';'*/)
{
if (Separator == '\0')
throw "Delimiter null";

int NumRows = 0;
char *Car = Txt;

// Calcul de la taille
while (Car != NULL) {
Car = strchr(++Car, Separator);
if (Car != NULL) { NumRows++; }
}

if (!NumRows) return 0; // Si pas de chaine a scindé , on sort.

NumRows++; //pour avoir le dernier "Mot" qui n'as pas de ';' en fin (en theorie)

Car = Txt; //Reinitialisation du pointeur

int lenWord = 0;
char *CarPtr = &(Txt[0]);
int i = 0;
int NumCar = 0;
int lenChar = strlen(&Separator); // toujours 1 mais au cas ou Separator != > char.

try {
return_value = new char * [NumRows]; //Allocation

// parcours a la recherche des chaines
while(i<NumRows) {
lenWord++;
if ((*Car == Separator) || (*Car==0)) {
return_value[i] = new char[lenWord];
strncpy(return_value[i], CarPtr, lenWord-lenChar);
CarPtr = &Txt[NumCar+lenChar];
lenWord = 0; //reinitialisation de la longueur de chaine
i++; //Element suivant dans le tableau
}
Car++; NumCar++;
};

} catch (...) {
delete [] return_value;
return 0;
}
return NumRows; // Renvoie du nombre de ligne;
}
cs_Lucky92
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Statut
Membre
Dernière intervention
16 août 2012
2 -
Le délimiteur de ta fonction explode se limite à un seul caractère. Que penses-tu d'étendre celui-ci à une chaîne de caractères, voire à une expression régulière comme en perl ?
guill76
Messages postés
193
Date d'inscription
mercredi 24 août 2005
Statut
Membre
Dernière intervention
3 juin 2016
-
je viens de metre à jour et d'optimiser un nouvel explode qui je pense est plus rapide que le précédent, je me suis un peu inspiré d'un autre code de brunews et j'ai rajouté la vraie gestion des champs csv avec la gestion des token.
l'allocation se fait dans le main: ce qui est + "conventionnel"

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.