IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Téléchargé 9 fois
Vote des utilisateurs
0 
0 
Détails
Licence : Non renseignée
Mise en ligne le 1er décembre 2010
Plate-formes : Linux, Mac, Windows
Langue : Français
Référencé dans
Navigation

Remplacer toutes les occurrences d'une sous-chaîne

Remplace toutes les occurrences de Avant par Apres dans la chaine txt, puis renvoie un pointeur sur la nouvelle chaîne créée. Renvoie NULL si txt ne contient aucune occurrence de Avant.
Avatar de cl8marti
Nouveau Candidat au Club https://www.developpez.com
Le 15/06/2016 à 9:11
Bonjour,
Très pratique cette fonction ! merci.
Cependant attention les valeurs de retour des allocations ne sont pas testés, elles sont suivis par des copies -> segfault.
Bonne journée
Avatar de Pyramidev
Expert éminent https://www.developpez.com
Le 15/06/2016 à 20:17
Bonjour,

Ton code actuel réussit bien les tests suivants :
Code : Sélectionner tout
1
2
3
4
5
char* res1 = str_replace("O_O_O_O_O_O", "O_O", "XY");
assert(0 == strcmp(res1, "XY_XY_XY"));

char* res2 = str_replace("O_O_O_O_O_O", "O_O", "");
assert(0 == strcmp(res2, "__"));
Dans la suite de mon message, je vais noter N le nombre d'occurrences de Avant dans txt.

Je propose les améliorations suivantes :
  • Si N est non nul, Ton code fait un appel à malloc et N+1 appels à realloc. Il serait plus performant de calculer N puis de faire une seule allocation :
    Code : Sélectionner tout
    TxtRetour = (char *) malloc(strlen(txt) - N*strlen(Avant) + N*strlen(Apres) + 1);
  • Si une allocation échoue, la fonction devrait retourner NULL.
  • Il y a un commentaire à corriger :
    Code : Sélectionner tout
    1
    2
    3
    4
    5
    /* Aucune occurrences : renvoie simplement une copie de la chaine */
    if (pos == NULL)
    {
        return NULL;
    }
    En effet, ce code ne renvoie pas une copie de la chaîne : il renvoie NULL.
  • Il y a un bout de ton code qui est de la forme :
    Code : Sélectionner tout
    1
    2
    3
    4
    5
    6
    BOUT_DE_CODE_B;
    while(condition)
    {
        BOUT_DE_CODE_A;
        BOUT_DE_CODE_B;
    }
    Dans ton cas, BOUT_DE_CODE_B est :
    Code : Sélectionner tout
    1
    2
    3
    4
    5
    6
    7
    /* Ajoute la chaîne de remplacement */
    Long = strlen (Apres);
    strncpy (TxtRetour + PosTxtRetour, Apres, Long);
    PosTxtRetour += Long;
    
    /* Cherche la prochaine occurrence */
    pos = strstr (txt, Avant);
    Ce code peut être factorisé, par exemple de cette manière :
    Code : Sélectionner tout
    1
    2
    3
    4
    5
    6
    7
    while(true)
    {
        BOUT_DE_CODE_B;
        if(!codition)
            break;
        BOUT_DE_CODE_A;
    }
  • Au début de ta fonction, je te conseille d'ajouter :
    Code : Sélectionner tout
    1
    2
    3
    assert(strlen(Avant) > 0);
    if(strlen(Avant) == 0)
        return NULL;
    Sinon, l'utilisateur risque d'être bloqué dans une boucle infinie.
  • Dans ton premier appel à realloc, tu as bien pensé à convertir le résultat en (char *). Il faudrait aussi le faire pour ton appel à malloc et ton autre appel à realloc. Ainsi, le code de ta fonction compilera aussi en C++.
  • Pour aller plus loin, tu pourrais factoriser le code en fournissant une nouvelle fonction str_replace_without_alloc utile aux utilisateurs qui voudraient gérer la mémoire autrement :
    Code : Sélectionner tout
    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
    // nombre d'occurrences de substring dans txt
    // retourner -1 si substring est une chaîne vide
    int str_count(const char *txt, const char *substring)
    {
        // ...
    }
    
    // remplacer toutes les occurrences de Avant par Apres dans la chaine txt
    // retourner false en cas d'erreur
    bool str_replace_without_alloc(char *Resultat, size_t tailleMaxResultat, const char *txt, const char *Avant, const char *Apres)
    {
        assert(Resultat != txt);
        // ...
    }
    
    char *str_replace(const char *txt, const char *Avant, const char *Apres)
    {
        char* TxtRetour = NULL;
    
        assert(strlen(Avant) > 0);
        if(strlen(Avant) == 0)
            return TxtRetour;
    
        const int N = str_count(txt, Avant);
        if(N <= 0)
            return TxtRetour;
    
        const size_t tailleTxtRetour = strlen(txt) - N*strlen(Avant) + N*strlen(Apres);
        TxtRetour = (char *) malloc(tailleTxtRetour + 1);
        if(TxtRetour == NULL)
            return TxtRetour;
    
        if(!str_replace_without_alloc(TxtRetour, tailleTxtRetour, txt, Avant, Apres)) {
            free(TxtRetour);
            TxtRetour = NULL;
        }
    
        return TxtRetour;
    }
Developpez.com décline toute responsabilité quant à l'utilisation des différents éléments téléchargés.