¿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

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. (Véase el algoritmo de Shlemiel, el pintor, sobre 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; } 

Esto no se proporciona en la biblioteca C estándar porque, dado solo un carácter *, no puede boost 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.

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, usaría strncpy .

No hay uno.

Tendrás que hacer el tuyo usando algo como strstr y strcat o strcpy.

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 desea replace_with sea ​​de la misma longitud que lo que desea replace , entonces probablemente sea mejor usar un nuevo buffer para copiar la nueva cadena.

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

 #include  #include  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  int main(int argc, char * argv[]) { if (argc != 4) { fprintf(stderr,"usage: %s   \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; } 
 // 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); } 

La función repl_str () en creativeandcritical.net es rápida y confiable. También se incluye en esa página una variante de cadena 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.

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

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 memory leaks.

  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. Por ejemplo, esto no funciona a menos que la persona que llama sabe que la línea es de 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é.

 /*замена символа в строке*/ char* replace_char(char* str, char in, char out) { char * p = str; while(p != '\0') { if(*p == in) *p == out; ++p; } return str; } 

Puede usar esta función (los comentarios explican cómo funciona):

 void strreplace(char *string, const char *find, const char *replaceWith){ if(strstr(string, replaceWith) != NULL){ char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1); strcpy(temporaryString, strstr(string, find) + strlen(find)); //Create a string with what's after the replaced part *strstr(string, find) = '\0'; //Take away the part to replace and the part after it in the initial string strcat(string, replaceWith); //Concat the first part of the string with the part to replace with strcat(string, temporaryString); //Concat the first part of the string with the part after the replaced part free(temporaryString); //Free the memory to avoid memory leaks } } 

una solución a la respuesta de fann95, utilizando la modificación in situ de la cadena, y suponiendo que el búfer al que apunta la línea es lo suficientemente grande como para contener la cadena resultante.

 static void replacestr(char *line, const char *search, const char *replace) { char *sp; if ((sp = strstr(line, search)) == NULL) { return; } int search_len = strlen(search); int replace_len = strlen(replace); int tail_len = strlen(sp+search_len); memmove(sp+replace_len,sp+search_len,tail_len+1); memcpy(sp, replace, replace_len); } 
 char *replace(char *instring,char *old,char *new) { if(!instring || !old || !new){ return (char*)NULL; } size_t instring_size=strlen(instring); size_t new_size=strlen(new); size_t old_size=strlen(old); size_t diffsize=new_size-old_size; size_t diffsizeAll=diffsize; size_t outstring_size=instring_size*2 + 1; char *outstring; char *test; test=(char*)malloc(old_size+1); outstring =(char*) malloc(outstring_size); if(!outstring || !test){ return (char*)NULL; } if(instring_size outstring_size) { outstring_size=outstring_size*2+1; outstring=realloc(outstring,outstring_size); if(!outstring){ free(test); return (char*)NULL; } } strcat(outstring,new); i=i+old_size-1; diffsizeAll=diffsizeAll+diffsize; }else{ test[1]='\0'; strcat(outstring,test); } } free(test); return outstring; } 

Aquí tienes … esta es la función para reemplazar cada aparición de char x con char y dentro de la cadena de caracteres str

 char *zStrrep(char *str, char x, char y){ char *tmp=str; while(*tmp) if(*tmp == x) *tmp++ = y; /* assign first, then incement */ else *tmp++; *tmp='\0'; return str; } 

Un ejemplo de uso podría ser

  Exmaple Usage char s[]="this is a trial string to test the function."; char x=' ', y='_'; printf("%s\n",zStrrep(s,x,y)); Example Output this_is_a_trial_string_to_test_the_function. 

La función es de una biblioteca de cadenas que mantengo en Github , es más que bienvenido echar un vistazo a otras funciones disponibles o incluso contribuir al código 🙂

https://github.com/fnoyanisi/zString

EDITAR: @siride tiene razón, la función anterior reemplaza a los caracteres solamente. Acabo de escribir este, que reemplaza las cadenas de caracteres.

 #include  #include  /* replace every occurance of string x with string y */ char *zstring_replace_str(char *str, const char *x, const char *y){ char *tmp_str = str, *tmp_x = x, *dummy_ptr = tmp_x, *tmp_y = y; int len_str=0, len_y=0, len_x=0; /* string length */ for(; *tmp_y; ++len_y, ++tmp_y) ; for(; *tmp_str; ++len_str, ++tmp_str) ; for(; *tmp_x; ++len_x, ++tmp_x) ; /* Bounds check */ if (len_y >= len_str) return str; /* reset tmp pointers */ tmp_y = y; tmp_x = x; for (tmp_str = str ; *tmp_str; ++tmp_str) if(*tmp_str == *tmp_x) { /* save tmp_str */ for (dummy_ptr=tmp_str; *dummy_ptr == *tmp_x; ++tmp_x, ++dummy_ptr) if (*(tmp_x+1) == '\0' && ((dummy_ptr-str+len_y) < len_str)){ /* Reached end of x, we got something to replace then! * Copy y only if there is enough room for it */ for(tmp_y=y; *tmp_y; ++tmp_y, ++tmp_str) *tmp_str = *tmp_y; } /* reset tmp_x */ tmp_x = x; } return str; } int main() { char s[]="Free software is a matter of liberty, not price.\n" "To understand the concept, you should think of 'free' \n" "as in 'free speech', not as in 'free beer'"; printf("%s\n\n",s); printf("%s\n",zstring_replace_str(s,"ree","XYZ")); return 0; } 

Y debajo está la salida

 Free software is a matter of liberty, not price. To understand the concept, you should think of 'free' as in 'free speech', not as in 'free beer' FXYZ software is a matter of liberty, not price. To understand the concept, you should think of 'fXYZ' as in 'fXYZ speech', not as in 'fXYZ beer' 
 DWORD ReplaceString(__inout PCHAR source, __in DWORD dwSourceLen, __in const char* pszTextToReplace, __in const char* pszReplaceWith) { DWORD dwRC = NO_ERROR; PCHAR foundSeq = NULL; PCHAR restOfString = NULL; PCHAR searchStart = source; size_t szReplStrcLen = strlen(pszReplaceWith), szRestOfStringLen = 0, sztextToReplaceLen = strlen(pszTextToReplace), remainingSpace = 0, dwSpaceRequired = 0; if (strcmp(pszTextToReplace, "") == 0) dwRC = ERROR_INVALID_PARAMETER; else if (strcmp(pszTextToReplace, pszReplaceWith) != 0) { do { foundSeq = strstr(searchStart, pszTextToReplace); if (foundSeq) { szRestOfStringLen = (strlen(foundSeq) - sztextToReplaceLen) + 1; remainingSpace = dwSourceLen - (foundSeq - source); dwSpaceRequired = szReplStrcLen + (szRestOfStringLen); if (dwSpaceRequired > remainingSpace) { dwRC = ERROR_MORE_DATA; } else { restOfString = CMNUTIL_calloc(szRestOfStringLen, sizeof(CHAR)); strcpy_s(restOfString, szRestOfStringLen, foundSeq + sztextToReplaceLen); strcpy_s(foundSeq, remainingSpace, pszReplaceWith); strcat_s(foundSeq, remainingSpace, restOfString); } CMNUTIL_free(restOfString); searchStart = foundSeq + szReplStrcLen; //search in the remaining str. (avoid loops when replWith contains textToRepl } } while (foundSeq && dwRC == NO_ERROR); } return dwRC; }