web-dev-qa-db-fra.com

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

J'essaie de créer une fonction en C pour remplacer toutes les occurrences d'une sous-chaîne dans une chaîne. J'ai créé ma fonction, mais cela ne fonctionne que lors de la première occurrence de la sous-chaîne dans la chaîne la plus grande.

Voici le code jusqu'à présent:

void strreplace(char string[], char search[], char replace[]){
    char buffer[100];
    char*p = string;
    while((p=strstr(p, search))){
        strncpy(buffer, string, p-string);
        buffer[p-string] = '\0'; //EDIT: THIS WAS MISSING
        strcat(buffer, replace);
        strcat(buffer, p+strlen(search));
        strcpy(string, buffer);
        p++;
    }
} 

Je ne suis pas nouveau en programmation C, mais il me manque quelque chose ici.

Exemple: pour la chaîne de saisie "marie a pommes a", recherche de "a" et remplace par "blabla"

Dans le premier "a" est remplacé correctement, mais le second ne l'est pas. Le résultat final est "marie blabla apple hasblabla". Remarquez que le deuxième "a" est toujours là.

Qu'est-ce que je fais mal? :)

EDIT Is fonctionne maintenant. L'ajout du caractère de fin nul a corrigé le problème. Je sais que la chaîne résultante peut être supérieure à 100. C'est un devoir de l'école et je n'aurai pas de chaîne supérieure à 20 ou plus.

5
Erik Blenert

Pour commencer:

Cette ligne 

strncpy(buffer, string, p-string);

pas nécessairement ajoute un 0- terminator à ce qui avait été copié dans buffer.

La ligne suivante

strcat(buffer, replace);

cependant, buffer étant 0- terminé.

Comme buffer n’a pas été initialisé et que le 0- terminator manque le plus probablement, cette dernière ligne peut très bien lire au-delà de la mémoire de buffer et ainsi appeler le tristement célèbre comportement indéfini.

4
alk

Il ne me semble pas clair quel algorithme vous essayez de suivre, cela me semble louche. Quelle est probablement l'approche la plus simple?

  • recherche de la première occurrence de "needle" (recherche de sous-chaîne)
  • copier la partie avant la première occurrence dans le tampon de résultat
  • ajoute la chaîne de remplacement au tampon de résultat
  • incrémente le pointeur p pour qu'il pointe juste après l'aiguille
  • GOTO 10
void str_replace(char *target, const char *needle, const char *replacement)
{
    char buffer[1024] = { 0 };
    char *insert_point = &buffer[0];
    const char *tmp = target;
    size_t needle_len = strlen(needle);
    size_t repl_len = strlen(replacement);

    while (1) {
        const char *p = strstr(tmp, needle);

        // walked past last occurrence of needle; copy remaining part
        if (p == NULL) {
            strcpy(insert_point, tmp);
            break;
        }

        // copy part before needle
        memcpy(insert_point, tmp, p - tmp);
        insert_point += p - tmp;

        // copy replacement string
        memcpy(insert_point, replacement, repl_len);
        insert_point += repl_len;

        // adjust pointers, move on
        tmp = p + needle_len;
    }

    // write altered string back to target
    strcpy(target, buffer);
}

Attention: Vous devez également faire attention à la façon dont vous appelez votre fonction. Si la chaîne de remplacement est plus grande que l'aiguille, votre chaîne modifiée sera plus longue que celle d'origine. Vous devez donc vous assurer que la mémoire tampon d'origine est suffisamment longue pour contenir la chaîne modifiée. Par exemple.:

char s[1024] = "marie has apples has";                         
str_replace(s, "has", "blabla");
char *replace_str(char *str, char *orig, char *rep)
{
static char buffer[4096];
char *p;
int i=0;

while(str[i]){
    if (!(p=strstr(str+i,orig)))  return str;
    strncpy(buffer+strlen(buffer),str+i,(p-str)-i);
    buffer[p-str] = '\0';
    strcat(buffer,rep);
    printf("STR:%s\n",buffer);
    i=(p-str)+strlen(orig);
}

return buffer;
}

int main(void)
{
  char str[100],str1[50],str2[50];
  printf("Enter a one line string..\n");
  gets(str);
  printf("Enter the sub string to be replaced..\n");
  gets(str1);
  printf("Enter the replacing string....\n");
  gets(str2);
  puts(replace_str(str, str1, str2));

  return 0;
}

Entrée: marie a des pommes a

Sortie: marie blabla pommes blabla 

3
StackUser
int replace_str(char* i_str, char* i_orig, char* i_rep)
{
   char l_before[2024];
   char l_after[2024];
   char* l_p;
   int l_origLen;

   l_origLen = strlen(i_orig);
   while (l_p = strstr(i_str, i_orig)) {
      sprintf(l_before ,"%.*s" ,l_p - i_str ,i_str);
      sprintf(l_after ,"%s" ,l_p + l_origLen);
      sprintf(i_str ,"%s%s%s" ,l_before ,i_rep ,l_after);
   }
   return(strlen(i_str));
}
0
Claudio