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

Présentation
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.
Téléchargement
Compatibilité
Linux Mac Windows
0  0 
Téléchargé 53 fois Voir les 2 commentaires
Détails
Avatar de haypo
Membre émérite
Voir tous les téléchargements de l'auteur
Licence : Autre
Date de mise en ligne : 1er décembre 2010




Avatar de cl8marti 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 Pyramidev - Membre chevronné 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.
Contacter le responsable de la rubrique C