124 votes

Quelle fonction permet de remplacer une sous-chaîne d'une chaîne en C ?

Étant donné un ( char * ), je veux trouver toutes les occurrences d'une sous-chaîne et les remplacer par une autre chaîne. Je ne vois pas de fonction simple qui permette de réaliser cela dans <string.h> .

114voto

jmucchiello Points 10521

L'optimiseur devrait éliminer la plupart des variables locales. Le pointeur tmp est là pour s'assurer que strcpy n'a pas à parcourir la chaîne pour trouver le null. tmp pointe vers la fin du résultat après chaque appel. (Voir L'algorithme de Shlemiel le peintre pour savoir pourquoi strcpy peut être ennuyeux).

// You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with) {
    char *result; // the return string
    char *ins;    // the next insert point
    char *tmp;    // varies
    int len_rep;  // length of rep (the string to remove)
    int len_with; // length of with (the string to replace rep with)
    int len_front; // distance between rep and end of last rep
    int count;    // number of replacements

    // sanity checks and initialization
    if (!orig || !rep)
        return NULL;
    len_rep = strlen(rep);
    if (len_rep == 0)
        return NULL; // empty rep causes infinite loop during count
    if (!with)
        with = "";
    len_with = strlen(with);

    // count the number of replacements needed
    ins = orig;
    for (count = 0; tmp = strstr(ins, rep); ++count) {
        ins = tmp + len_rep;
    }

    tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);

    if (!result)
        return NULL;

    // first time through the loop, all the variable are set correctly
    // from here on,
    //    tmp points to the end of the result string
    //    ins points to the next occurrence of rep in orig
    //    orig points to the remainder of orig after "end of rep"
    while (count--) {
        ins = strstr(orig, rep);
        len_front = ins - orig;
        tmp = strncpy(tmp, orig, len_front) + len_front;
        tmp = strcpy(tmp, with) + len_with;
        orig += len_front + len_rep; // move to next "end of rep"
    }
    strcpy(tmp, orig);
    return result;
}

21voto

Don Neufeld Points 12803

Cette fonction n'est pas fournie dans la bibliothèque C standard parce que, étant donné seulement un char*, vous ne pouvez pas augmenter la mémoire allouée à la chaîne si la chaîne de remplacement est plus longue que la chaîne remplacée.

Vous pouvez le faire en utilisant std::string plus facilement, mais même dans ce cas, aucune fonction unique ne le fera pour vous.

14voto

Reed Copsey Points 315315

Il n'y en a pas.

Vous devez créer le vôtre en utilisant quelque chose comme strstr et strcat ou strcpy.

12voto

Brian R. Bondy Points 141769

Vous pourriez construire votre propre fonction de remplacement en utilisant strstr pour trouver les sous-chaînes et strncpy pour copier les parties dans un nouveau tampon.

A moins que ce que vous voulez replace_with est de la même longueur que ce que vous voulez replace alors il est probablement préférable d'utiliser un nouveau tampon pour y copier la nouvelle chaîne.

11voto

rampion Points 38697

Voici un exemple de code qui le fait.

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

char * replace(
    char const * const original, 
    char const * const pattern, 
    char const * const replacement
) {
  size_t const replen = strlen(replacement);
  size_t const patlen = strlen(pattern);
  size_t const orilen = strlen(original);

  size_t patcnt = 0;
  const char * oriptr;
  const char * patloc;

  // find how many times the pattern occurs in the original string
  for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
  {
    patcnt++;
  }

  {
    // allocate memory for the new string
    size_t const retlen = orilen + patcnt * (replen - patlen);
    char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) );

    if (returned != NULL)
    {
      // copy the original string, 
      // replacing all the instances of the pattern
      char * retptr = returned;
      for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
      {
        size_t const skplen = patloc - oriptr;
        // copy the section until the occurence of the pattern
        strncpy(retptr, oriptr, skplen);
        retptr += skplen;
        // copy the replacement 
        strncpy(retptr, replacement, replen);
        retptr += replen;
      }
      // copy the rest of the string.
      strcpy(retptr, oriptr);
    }
    return returned;
  }
}

#include <stdio.h>
int main(int argc, char * argv[])
{
  if (argc != 4)
  {
    fprintf(stderr,"usage: %s <original text> <pattern> <replacement>\n", argv[0]);
    exit(-1);
  }
  else
  {
    char * const newstr = replace(argv[1], argv[2], argv[3]);
    if (newstr)
    {
      printf("%s\n", newstr);
      free(newstr);
    }
    else
    {
      fprintf(stderr,"allocation error\n");
      exit(-2);
    }
  }
  return 0;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X