Pregunta ¿Cuál es la función para reemplazar cadena en C?


Dada una cadena (char *), quiero encontrar toda la ocurrencia de una subcadena y reemplazarla por una cadena alternativa. No veo ninguna función simple que logre esto en <string.h>


74
2018-04-23 00:48


origen


Respuestas:


El optimizador debería eliminar la mayoría de las variables locales. El puntero tmp está ahí para asegurarse de que strcpy no tenga que recorrer la cadena para encontrar el nulo. tmp apunta al final del resultado después de cada llamada. (Ver Shlemiel el algoritmo del pintor por qué strcpy puede ser molesto.)

// 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;
}

70
2018-04-23 01:28



Esto no se proporciona en la biblioteca C estándar porque, dado solo un carácter *, no puede aumentar la memoria asignada a la cadena si la cadena de reemplazo es más larga que la cadena que se reemplaza.

Puede hacer esto usando std :: string más fácilmente, pero incluso allí, ninguna función lo hará por usted.


22
2018-04-23 00:53



Como las cadenas en C no pueden crecer dinámicamente en el lugar, la sustitución generalmente no funcionará. Por lo tanto, debe asignar espacio para una nueva cadena que tenga suficiente espacio para su sustitución y luego copiar las partes del original más la sustitución en la nueva cadena. Para copiar las partes que usarías strncpy.


9
2018-04-23 00:54



No hay uno.

Tendrás que hacer tu propio uso de algo como strstr y strcat o strcpy.


8
2018-04-23 00:52



Puedes construir tu propia función de reemplazo usando strstr para encontrar las subcadenas y strncpy para copiar partes en un nuevo buffer.

A menos que lo que quieras replace_with es la misma longitud que lo que desea replace, entonces probablemente sea mejor usar un nuevo buffer para copiar la nueva cadena.


8
2018-04-23 00:51



Aquí hay un código de muestra que lo hace.

#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;
}

7
2018-04-23 01:56



// Here is the code for unicode strings!


int mystrstr(wchar_t *txt1,wchar_t *txt2)
{
    wchar_t *posstr=wcsstr(txt1,txt2);
    if(posstr!=NULL)
    {
        return (posstr-txt1);
    }else
    {
        return -1;
    }
}

// assume: supplied buff is enough to hold generated text
void StringReplace(wchar_t *buff,wchar_t *txt1,wchar_t *txt2)
{
    wchar_t *tmp;
    wchar_t *nextStr;
    int pos;

    tmp=wcsdup(buff);

    pos=mystrstr(tmp,txt1);
    if(pos!=-1)
    {
        buff[0]=0;
        wcsncpy(buff,tmp,pos);
        buff[pos]=0;

        wcscat(buff,txt2);

        nextStr=tmp+pos+wcslen(txt1);

        while(wcslen(nextStr)!=0)
        {
            pos=mystrstr(nextStr,txt1);

            if(pos==-1)
            {
                wcscat(buff,nextStr);
                break;
            }

            wcsncat(buff,nextStr,pos);
            wcscat(buff,txt2);

            nextStr=nextStr+pos+wcslen(txt1);   
        }
    }

    free(tmp);
}

4
2018-06-03 03:38



los repl_str () la función en creativeandcritical.net es rápida y confiable. También se incluye en esa página una variante de cuerda ancha, repl_wcs (), que se puede usar con cadenas Unicode incluidas las codificadas en UTF-8, a través de funciones auxiliares, el código de demostración se vincula desde la página. Revelación completa tardía: soy el autor de esa página y las funciones que contiene.


3
2018-02-03 22:59



Encuentro que la mayoría de las funciones propuestas son difíciles de entender, así que se me ocurrió esto:

static char *dull_replace(const char *in, const char *pattern, const char *by)
{
    size_t outsize = strlen(in) + 1;
    // TODO maybe avoid reallocing by counting the non-overlapping occurences of pattern
    char *res = malloc(outsize);
    // use this to iterate over the output
    size_t resoffset = 0;

    char *needle;
    while (needle = strstr(in, pattern)) {
        // copy everything up to the pattern
        memcpy(res + resoffset, in, needle - in);
        resoffset += needle - in;

        // skip the pattern in the input-string
        in = needle + strlen(pattern);

        // adjust space for replacement
        outsize = outsize - strlen(pattern) + strlen(by);
        res = realloc(res, outsize);

        // copy the pattern
        memcpy(res + resoffset, by, strlen(by));
        resoffset += strlen(by);
    }

    // copy the remaining input
    strcpy(res + resoffset, in);

    return res;
}

la salida debe ser libre


2
2018-03-09 21:14



Aquí está el que creé basado en estos requisitos:

  1. Reemplace el patrón independientemente de si fue largo o más corto.

  2. No use ningún malloc (explícito o implícito) para evitar intrínsecamente fugas de memoria.

  3. Reemplace cualquier cantidad de ocurrencias de patrón.

  4. Tolere la cadena de reemplazo que tiene una subcadena igual a la cadena de búsqueda.

  5. No tiene que verificar que la matriz Line sea suficiente para contener el reemplazo. p.ej. Esto no funciona a menos que la persona que llama sepa que la línea tiene el tamaño suficiente para contener la nueva cadena.

/* returns number of strings replaced.
*/
int replacestr(char *line, const char *search, const char *replace)
{
   int count;
   char *sp; // start of pattern

   //printf("replacestr(%s, %s, %s)\n", line, search, replace);
   if ((sp = strstr(line, search)) == NULL) {
      return(0);
   }
   count = 1;
   int sLen = strlen(search);
   int rLen = strlen(replace);
   if (sLen > rLen) {
      // move from right to left
      char *src = sp + sLen;
      char *dst = sp + rLen;
      while((*dst = *src) != '\0') { dst++; src++; }
   } else if (sLen < rLen) {
      // move from left to right
      int tLen = strlen(sp) - sLen;
      char *stop = sp + rLen;
      char *src = sp + sLen + tLen;
      char *dst = sp + rLen + tLen;
      while(dst >= stop) { *dst = *src; dst--; src--; }
   }
   memcpy(sp, replace, rLen);

   count += replacestr(sp + rLen, search, replace);

   return(count);
}

Cualquier sugerencia para mejorar este código se acepta alegremente. Solo publique el comentario y lo probaré.


1
2017-08-02 19:09