begin process at 2010 03 21 16:24:28
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Chaîne de caractères

 > SPLIT/EXPLODE D'UNE CHAINE DE CARACTERE EN C

SPLIT/EXPLODE D'UNE CHAINE DE CARACTERE EN C


 Information sur la source

Note :
8,67 / 10 - par 3 personnes
8,67 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Chaîne de caractères Classé sous :split, explode, chaine, string, délimiteur Niveau :Débutant Date de création :17/08/2005 Date de mise à jour :17/08/2005 14:31:40 Vu / téléchargé :23 747 / 296

Auteur : goth

Ecrire un message privé
Commentaire sur cette source (14)
Ajouter un commentaire et/ou une note

 Description

Suite à la question que j'ai posé sur le forum, j'ai fait une petite
fonction qui découpe une chaine suivant un délimiteur.
La fonction permet de choisir si on accpete ou non les mots vides.
Elle retourne un tableau de chaines de caractères, terminé par NULL.

Le code est compilé sous windows avec gcc donc la fonction doit être portable sous linux/unix.
(quoique que j'ai des doutes sur system("pause") )

Source

  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>
  • // Retour tableau des chaines recupérer. Terminé par NULL.
  • // chaine : chaine à splitter
  • // delim : delimiteur qui sert à la decoupe
  • // vide : 0 : on n'accepte pas les chaines vides
  • // 1 : on accepte les chaines vides
  • char** split(char* chaine,const char* delim,int vide){
  • char** tab=NULL; //tableau de chaine, tableau resultat
  • char *ptr; //pointeur sur une partie de
  • int sizeStr; //taille de la chaine à recupérer
  • int sizeTab=0; //taille du tableau de chaine
  • char* largestring; //chaine à traiter
  • int sizeDelim=strlen(delim); //taille du delimiteur
  • largestring = chaine; //comme ca on ne modifie pas le pointeur d'origine
  • //(faut ke je verifie si c bien nécessaire)
  • while( (ptr=strstr(largestring, delim))!=NULL ){
  • sizeStr=ptr-largestring;
  • //si la chaine trouvé n'est pas vide ou si on accepte les chaine vide
  • if(vide==1 || sizeStr!=0){
  • //on alloue une case en plus au tableau de chaines
  • sizeTab++;
  • tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
  • //on alloue la chaine du tableau
  • tab[sizeTab-1]=(char*) malloc( sizeof(char)*(sizeStr+1) );
  • strncpy(tab[sizeTab-1],largestring,sizeStr);
  • tab[sizeTab-1][sizeStr]='\0';
  • }
  • //on decale le pointeur largestring pour continuer la boucle apres le premier elément traiter
  • ptr=ptr+sizeDelim;
  • largestring=ptr;
  • }
  • //si la chaine n'est pas vide, on recupere le dernier "morceau"
  • if(strlen(largestring)!=0){
  • sizeStr=strlen(largestring);
  • sizeTab++;
  • tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
  • tab[sizeTab-1]=(char*) malloc( sizeof(char)*(sizeStr+1) );
  • strncpy(tab[sizeTab-1],largestring,sizeStr);
  • tab[sizeTab-1][sizeStr]='\0';
  • }
  • else if(vide==1){ //si on fini sur un delimiteur et si on accepte les mots vides,on ajoute un mot vide
  • sizeTab++;
  • tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
  • tab[sizeTab-1]=(char*) malloc( sizeof(char)*1 );
  • tab[sizeTab-1][0]='\0';
  • }
  • //on ajoute une case à null pour finir le tableau
  • sizeTab++;
  • tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
  • tab[sizeTab-1]=NULL;
  • return tab;
  • }
  • int main(){
  • int i;
  • int ret;
  • char* str="foo|bar||baz|bar|";
  • char** tab;
  • printf("Chaine initiale : %s \n",str);
  • tab=split(str,"|",0);
  • //affichage du resultat
  • for(i=0;tab[i]!=NULL;i++) {
  • printf("%d : %s\n",i,tab[i]);
  • //au passge je désalloue les chaines
  • free(tab[i]);
  • }
  • free(tab);
  • printf("\n");
  • tab=split(str,"|",1);
  • //affichage du resultat
  • for(i=0;tab[i]!=NULL;i++) {
  • printf("%d : %s\n",i,tab[i]);
  • //au passge je désalloue les chaines
  • free(tab[i]);
  • }
  • free(tab);
  • system("pause");
  • }
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Retour tableau des chaines recupérer. Terminé par NULL.
// chaine : chaine à splitter
// delim : delimiteur qui sert à la decoupe
// vide : 0 : on n'accepte pas les chaines vides
//        1 : on accepte les chaines vides
char** split(char* chaine,const char* delim,int vide){
    
    char** tab=NULL;                    //tableau de chaine, tableau resultat
    char *ptr;                     //pointeur sur une partie de
    int sizeStr;                   //taille de la chaine à recupérer
    int sizeTab=0;                 //taille du tableau de chaine
    char* largestring;             //chaine à traiter
    
    int sizeDelim=strlen(delim);   //taille du delimiteur


    largestring = chaine;          //comme ca on ne modifie pas le pointeur d'origine
                                   //(faut ke je verifie si c bien nécessaire)
    

    while( (ptr=strstr(largestring, delim))!=NULL ){
           sizeStr=ptr-largestring;
     
           //si la chaine trouvé n'est pas vide ou si on accepte les chaine vide                   
           if(vide==1 || sizeStr!=0){
               //on alloue une case en plus au tableau de chaines
               sizeTab++;
               tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
                              
               //on alloue la chaine du tableau
               tab[sizeTab-1]=(char*) malloc( sizeof(char)*(sizeStr+1) );
               strncpy(tab[sizeTab-1],largestring,sizeStr);
               tab[sizeTab-1][sizeStr]='\0';
           }
           
           //on decale le pointeur largestring  pour continuer la boucle apres le premier elément traiter
           ptr=ptr+sizeDelim;
           largestring=ptr;
    }
    
    //si la chaine n'est pas vide, on recupere le dernier "morceau"
    if(strlen(largestring)!=0){
           sizeStr=strlen(largestring);
           sizeTab++;
           tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
           tab[sizeTab-1]=(char*) malloc( sizeof(char)*(sizeStr+1) );
           strncpy(tab[sizeTab-1],largestring,sizeStr);
           tab[sizeTab-1][sizeStr]='\0';
    }
    else if(vide==1){ //si on fini sur un delimiteur et si on accepte les mots vides,on ajoute un mot vide
           sizeTab++;
           tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
           tab[sizeTab-1]=(char*) malloc( sizeof(char)*1 );
           tab[sizeTab-1][0]='\0';
           
    }
    
    //on ajoute une case à null pour finir le tableau
    sizeTab++;
    tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
    tab[sizeTab-1]=NULL;

    return tab;
}

int main(){
    int i;
    int ret;
    char* str="foo|bar||baz|bar|";
    char** tab;
    
    printf("Chaine initiale : %s \n",str);
    
    tab=split(str,"|",0);
    //affichage du resultat
    for(i=0;tab[i]!=NULL;i++) {
       printf("%d : %s\n",i,tab[i]);
       //au passge je désalloue les chaines
       free(tab[i]);
    }
    free(tab);
    
    printf("\n");
    
    tab=split(str,"|",1);
    //affichage du resultat
    for(i=0;tab[i]!=NULL;i++) {
       printf("%d : %s\n",i,tab[i]);
       //au passge je désalloue les chaines
       free(tab[i]);
    }
    free(tab);
    
    system("pause");

}

 Conclusion

Le tableau est alloué dynamiquement => n'oubliez pas de désallouer.

Merci à buno et steve_clamage pour leur info sur le forum.

Puis si vous trouver des bug ou si vous voulez noter, un chtit commentaire.

Voila a quoi ressemble la sortie :
chaine init : foo|bar||baz|bar|
0 : foo
1 : bar
2 : baz
3 : bar

0 : foo
1 : bar
2 :
3 : baz
4 : bar
5 :
Appuyez sur une touche pour continuer...

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

17 août 2005 14:31:40 :
- Rajout d'un zip pour ceux que ca interresse - Exemple de sortie du programme, pour voir ce que ca fait concrètement

 Sources de la même categorie

FONCTION : CHAR * AJUSTERTAILLECHAINE() par Rockanos
Source avec Zip RECHERCHE D'ANNAGRAMMES par Torin
GESTION DE CHAINE DE CARACTÉRE EN C++ AVEC NSTRING par xmustapha
Source avec Zip COMMENTER CODE C <=> ASM (WIN64) par BruNews
Source avec Zip GSTRING - GESTION DES CHAINES DE CARACTÈRES par Neokript

 Sources en rapport avec celle ci

Source avec Zip GSTRING - GESTION DES CHAINES DE CARACTÈRES par Neokript
SIMPLE FONCTION TOKENIZE par spidermario
Source avec Zip MYSTRING, CLASSE TRAITANT DES CHAÎNES DE CARACTÈRES par Noubzor
Source avec Zip Source avec une capture [C/WIN32] GÉNÉRATEUR DE CODE POUR UNE INITIALISATION SPÉCIAL... par deck_bsd
SPLIT EN C++ AVEC LES CONTENEURS STANDARD par CChargy

Commentaires et avis

Commentaire de Hylvenir le 17/08/2005 22:52:40

Salut,

c'est un peu compliqué pour juste la suppression du static
de l'exemple http://cppfrance.com/code.aspx?id=28947

Tu aurais sûrement pu faire une fonction unique pour le realloc si besoin.

Dans ton test, tu ne profites pas de la possiblité d'avoir un séparateur de plusieurs caractères. Domamge.

Par contre, bien le main qui lance la fonction, ça aurait été parfait,
avec un test automatique vérifiant les résultats mais je chipote ;)

L'idée du vide est original (par exemple strtok n'accepte pas) mais est-ce utile ? J'imagine un fichier csv pour lequel on sauterait les
colonnes vide ( ;; ). pas top ? Mais c'est peut être bien d'avoir le choix.

La signature de tes fonction devrait probablement être const char*, const char*, int. Il semble qu'il manque un const.

Les multiples realloc font que c'est assez pénible à utiliser au retour (avec des free en boucle)? il n'y a pas mieux ?

Cordialement.

Commentaire de goth le 18/08/2005 09:48:44

en fait j'ai réessayer de fai re le fonction explode comme on la trouve en php, donc a l'origine en gardant les mots vides (comme tu l'a dit ca peu etre utile pour un csv ou fichier de config qqconque.

==>Tu aurais sûrement pu faire une fonction unique pour le realloc si besoin.
tu entends quoi par la?

==> si on rajoute const au param shaine, il faut que largestring soit aussi en const sinon il y a un warning.
Mais question....ca change quoi de mettre en const char *.

==>en ca qui conscerne la taille du séparateur tu peux tres bien avoir une chaine comme séparateur. Essaie de mettre bar comme séparateur (dans l'exempel ca va de soit) et tu aura comme sortie :
Chaine
0 : fo
1 : ||
2 : |

pour finir avec le problème du free en boucle, je voulais que la fonction soit dynamique au possible...j'aurais pu allouer par plus gros bloc puis désallouer le surplus en fin, mais bon...
Puis pour les free...ben fau bien liberer la memoire allouer...sinon comment tu veux faire?

goth

Commentaire de meech le 18/08/2005 15:44:19

Salut,

1. Pour la question de la différence entre "const char*" et "char*", je cite :

"Une variable dont le type est qualifié par const ne peut pas être modifiée. Ce qualificateur est utilisé pour se protéger d'une erreur de programmation. On l'emploie principalement pour qualifier le type des paramètres d'une fonction afin d'éviter de les modifier involontairement."

2. Je ne comprends pas bien le problème de la boucle "free". Comment faire autrement, mis à part automatiser la désallocation dans une fonction ?

3. Un bon code très utile.

Commentaire de Hylvenir le 19/08/2005 00:12:23

goth > l'idéal pour refaire la fonction PHP, c'est d'utiliser le C++ avec std::string et std::vector comme ça le principal problème d'allocation/réallocation est résolu.

Meech, la désallocation en boucle est désagréable pour un utilisateur surtout si la boucle d'affichage et la boucle de désallocation sont séparées.

Voici une autre version, un peu plus courte,
qui n'impose pas la boucle de free en modifiant la chaîne entrée en param. le param vide est traité même si pas très utile à mon sens en pratique.
A vous de voir.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// La chaine à splitter qui sera modifée
char** split( char* str, const char* c, int vide )
{
    int currentSplitSize = 8;
    char** currentSplit  = malloc( currentSplitSize * sizeof(char*) );

    int sizeSeparateur = strlen( c );
    int current = 0;
    currentSplit[current++] = str;

    while( str = strstr( str, c ) )
    {
        *str = '\0';
        str += sizeSeparateur;

        // Si on ne veut pas des chaines vide, et si la chaine
        // précédente est vide alors, on recule pour l'effacer
        if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
            --current;

        // On pointe vers le nouveau début
        currentSplit[ current++ ] = str;
        
        // On agrandit le tableau si trop petit en le doublant
        if ( current > currentSplitSize - 1 )
        {
            currentSplitSize <<=2;
            currentSplit = realloc( currentSplit,
                                    currentSplitSize * sizeof(char*) );
        }
    }

    // La dernière chaine peut etre vide, on recule pour la supprimer
    if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
        --current;

    // On termine le tableau
    currentSplit[ current ] = 0;
    return currentSplit;
}

int main(){
    int i;
    char str[]="foo|bar||baz|bar|";

    printf("Chaine initiale : %s \n",str);
    
    char** tab = split( str, "|", 0 );
    for(i=0;tab[i];i++) {
       printf("%d : %s\n",i,tab[i]);
    }
    free(tab);
    
    printf("\n");
    
    char str2[]="foo|bar||baz|bar|";
    tab=split(str2,"|",1);

    for(i=0;tab[i];i++) {
       printf("%d : %s\n",i,tab[i]);
    }
    free(tab);
}

Commentaire de Hylvenir le 19/08/2005 00:16:31

Au fait, voici la correction pour
le cas du séparateur bar ;)

Chaine initiale : foo|bar||baz|bar|
0 : foo|
1 : ||baz|
2 : |

Commentaire de goth le 19/08/2005 09:29:45

pour la refonte en c++, la je developpe en C, c le pourquoi du comment.
Puis ta fonction marche bien, mais, à mon avis le pb,si c'en est un, c que tu réutilise la même chaine str (d'ou l'économie de malloc)
Mais bon, ca marche c l'important non?

Commentaire de Hylvenir le 19/08/2005 10:05:39

C'est jamais important que ça marche, c'est le minimum que ça marche.
A quoi peut bien servir du code qui ne marche pas ?

L'important c'est que ça soit utilisable, lisible, maintenable, souple,...
ça c'est important et toute la difficulté à mon sens.

Le fait d'utiliser la chaîne passée en entrée permet justement
d'éviter d'avoir la responsabilibité de l'allocation et la boucle
pour libérer la mémoire.

PS : les 2 lignes : if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
se remplacent par : if ( !vide && ( !*currentSplit[ current-1 ] ) )

PPS: J'ai omis le test sur les retours d'allocation car non présent dans le code original.

Commentaire de meech le 19/08/2005 10:54:40

Goth > conernant la désallocation, tu as raison, je n'avais pas vu les choses comme cela. Pas mal du tout, ton code.

Commentaire de Hylvenir le 22/08/2005 18:43:35

Mon code étant buggué, je le corrige.
J'ai supprimé le realloc qui peut être pénalisant pour les perfs.

// ---------------------------------------------------------------------
char** split( char* str, const char* separator, int removeEmptyField )
{
    size_t sizeSeparator = strlen( separator );
    char** currentSplit  = 0;
    size_t nbSep = 0, nbEmptyField = 0, sizeSplit = 0, currentSep = 0;
    char* pos = str, *currentPos = str;

    // Compte le nombre séparateur, le nombre de champs vide
    // et le séparateur par des '\0'
    while( pos = strstr( pos, separator ) ) {
        memset( pos, '\0', sizeSeparator );
        if ( pos == str || ( pos != str && !*(pos-1) ) )
            ++nbEmptyField;

        ++nbSep;
        currentPos = (pos += sizeSeparator);
    }
    if ( currentPos == str || ( currentPos != str && !*currentPos ) )
        ++nbEmptyField;

    // Calcul la taille du tableau final
    sizeSplit = nbSep+1 - (removeEmptyField?nbEmptyField:0);
    if ( !sizeSplit ) return 0;
    
    // Alloue le tableau des pointeurs
    currentSplit = malloc( (sizeSplit+1) * sizeof(char*) );
    if ( !currentSplit ) return 0;

    // Affecte les entrées du tableau
    pos = str;
    while( currentSep < sizeSplit ) {
        if ( !( removeEmptyField && !*pos ) )
            currentSplit[currentSep++] = pos;

        while( *pos++ );
        pos += sizeSeparator - 1;
    }
    return currentSplit;
}

Commentaire de kazoumoulox le 10/04/2006 09:04:34

salut... j'avais besoin d'une fonction explode en C, similaire a celle du php. En fait je récupère le contenu affiché dans la console d'un batch (de ftp) que je lance dans mon prog. Je récupère donc ce contenu dans un fichier, puis je l'ouvre et je fait un fgets sur chaque ligne... et donc je peux récuperer la liste des fichiers que j'obtiens en faisant un ls quand je suis connecté... je mets dans un buffer la sortie de ce fgets(), et je fais un explode(grace a cette fonction au dessus), pour avoir l'extension des fichiers (je ne veux que les txt)... mais la j'ai un pb... il me sort que le nom de fichier est, a chaque fois, "2292832"...et que l'extension est bien "TXT". comment ca se fait, pour le nom de fichier??? si kkun a une idée?? je sèche...

Commentaire de kazoumoulox le 10/04/2006 09:33:14

suite du message précédent : apparemment ya un ptit probleme, en fait je ne peux pas accéder a tab[i], au i eme element de la chaine créée, est ce que ca vient de mon strcpy que je fais pour copier le buffer dans la chaine ou autre chose???

Commentaire de kazoumoulox le 10/04/2006 10:10:15

re re salut..bon en fait g capté le pb!! trop nul moi en C...en fait j'affichais pas le bon truc,... un %c au lieu d'un %s dans le printf, du coup me fesait envoyer paitre...alors dsl pour toutes ces questions inutiles...
mais je rajoute que l'explode marche nikel!!! merci les coupains!

Commentaire de oliver7 le 16/09/2006 19:49:31

slt
J'essay d'utiliser ton code mais j'ai un petit souci.
Mon code :

char** tableau;
tableau = split("TESTE;rien",";",0);
if (tableau[0] == "TESTE")
{
   printf("%s",tableau[0]);
} else {
   printf("1er tableau n'est pas teste0");
}

Mon probleme est qu'il fait toujours le else, pourquoi ?

Commentaire de goth le 18/09/2006 23:27:52

lol,ca t'a dit quelque les fonction pour manipuler les chaines en C?
Essaie man 3 strcmp dans google

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

split/explode d'une chaine [ par goth ] bonjour tt le monde, je cherche une fonction qui ferait a peu pres la m&#234;me chose que explode en php, &nbsp;a savoir decouper une chaine suivant u [FUNCTION] : Problème de déclaration [ par Alex120 ] Bonjour, J'ai écrit une fonction split() dans un fichier cpp : #include &lt;clx.h&gt; #include "vector.h" /** * FUNCTION SPLIT() */ vo Traiter une chaine en c++ [ par drnicholas001 ] Salut, je veux me faire un petit programme qui fonctionne en ligne de commande, donc lutilisateur &#233;crit en mode console : solve(x-2=0, x) et le p Recuper une chaine contenu dans un string [ par clcat ] Bonjour a tous,Le probleme est simple je pense (je programme en C++) :j'ai cette ligne la : node = insDoc(aux1, gLnk("&lt;FONT class='FTFONT'&gt;GPFD& probleme d'une chaine de caracteres [ par bilaloch ] Bonjour a tous,J'ai un ptit probleme au niveau d'une manipulation sur une chaine de caracteres. Voici le code : std::string *position = <FONT color=# Split de chaine de caracteres [ par lektrosonic ] Existe-il une fonction predefinie qui transforme char[ ]="ceci|est|une|chaine|separee/0"  en char1[]="ceci", char2[]="est" .... ?l3KTr0 Was HeRe C string compare [ par Yunchi ] Bonjour, Je recherche une fonction dans le bibliotheque string.h ou autre qui permettrait en fait de savoir si une chaine est presente dans une autre explode [ par thebigbang ] bonjour à tous,Je cherche une fonction C++ qui permettrait de créer des tableaux de chaine à partir d'une autre chaine que l'on aurait découpée en fon explode [ par thebigbang ] bonjour à tous,Je cherche une fonction C++ qui permettrait de créer des tableaux de chaine à partir d'une autre chaine que l'on aurait découpée en fon Convertion d'une string en char [ par redpooka ] Voici avec ce programme ca n'affiche juste le premier charactère comment faire pour qu'il affiche toute la chaine de caracètre ?Merci#include &lt;iost


Nos sponsors


Sondage...

CalendriCode

Mars 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728
293031    

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,406 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales