1.11M Members

Strings: Search and Replace

 
0
 

Finding some text and replacing it with new text within a C string can be a little trickier than expected. Here is what I had come up with one day.

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

/*
 * Description:
 *   Find and replace text within a string.
 *
 * Parameters:
 *   src  (in) - pointer to source string
 *   from (in) - pointer to search text
 *   to   (in) - pointer to replacement text
 *
 * Returns:
 *   Returns a pointer to dynamically-allocated memory containing string
 *   with occurences of the text pointed to by 'from' replaced by with the
 *   text pointed to by 'to'.
 */
char *replace(const char *src, const char *from, const char *to)
{
   /*
    * Find out the lengths of the source string, text to replace, and
    * the replacement text.
    */
   size_t size    = strlen(src) + 1;
   size_t fromlen = strlen(from);
   size_t tolen   = strlen(to);
   /*
    * Allocate the first chunk with enough for the original string.
    */
   char *value = malloc(size);
   /*
    * We need to return 'value', so let's make a copy to mess around with.
    */
   char *dst = value;
   /*
    * Before we begin, let's see if malloc was successful.
    */
   if ( value != NULL )
   {
      /*
       * Loop until no matches are found.
       */
      for ( ;; )
      {
         /*
          * Try to find the search text.
          */
         const char *match = strstr(src, from);
         if ( match != NULL )
         {
            /*
             * Found search text at location 'match'. :)
             * Find out how many characters to copy up to the 'match'.
             */
            size_t count = match - src;
            /*
             * We are going to realloc, and for that we will need a
             * temporary pointer for safe usage.
             */
            char *temp;
            /*
             * Calculate the total size the string will be after the
             * replacement is performed.
             */
            size += tolen - fromlen;
            /*
             * Attempt to realloc memory for the new size.
             */
            temp = realloc(value, size);
            if ( temp == NULL )
            {
               /*
                * Attempt to realloc failed. Free the previously malloc'd
                * memory and return with our tail between our legs. :(
                */
               free(value);
               return NULL;
            }
            /*
             * The call to realloc was successful. :) But we'll want to
             * return 'value' eventually, so let's point it to the memory
             * that we are now working with. And let's not forget to point
             * to the right location in the destination as well.
             */
            dst = temp + (dst - value);
            value = temp;
            /*
             * Copy from the source to the point where we matched. Then
             * move the source pointer ahead by the amount we copied. And
             * move the destination pointer ahead by the same amount.
             */
            memmove(dst, src, count);
            src += count;
            dst += count;
            /*
             * Now copy in the replacement text 'to' at the position of
             * the match. Adjust the source pointer by the text we replaced.
             * Adjust the destination pointer by the amount of replacement
             * text.
             */
            memmove(dst, to, tolen);
            src += fromlen;
            dst += tolen;
         }
         else /* No match found. */
         {
            /*
             * Copy any remaining part of the string. This includes the null
             * termination character.
             */
            strcpy(dst, src);
            break;
         }
      }
   }
   return value;
}

void test(const char *source, const char *search, const char *repl)
{
   char *after;
   after = replace(source, search, repl);
   printf("\nsearch = \"%s\", repl = \"%s\"\n", search, repl);
   if ( after != NULL )
   {
      printf("after  = \"%s\"\n", after);
      free(after);
   }
}

int main(void)
{
   const char before[] = "the rain in Spain falls mainly on the plain";
   printf("before = \"%s\"\n", before);
   test(before, "the", "THEE");
   test(before, "the", "A");
   test(before, "cat", "DOG");
   test(before, "plain", "PLANE");
   test(before, "ain", "AINLY");
   return 0;
}

/* my output
before = "the rain in Spain falls mainly on the plain"

search = "the", repl = "THEE"
after  = "THEE rain in Spain falls mainly on THEE plain"

search = "the", repl = "A"
after  = "A rain in Spain falls mainly on A plain"

search = "cat", repl = "DOG"
after  = "the rain in Spain falls mainly on the plain"

search = "plain", repl = "PLANE"
after  = "the rain in Spain falls mainly on the PLANE"

search = "ain", repl = "AINLY"
after  = "the rAINLY in SpAINLY falls mAINLYly on the plAINLY"
*/
 
0
 

the function above have some bugs.... it fails for example with this:
replace("1.2.3.4.5.6.7.8.9",".","abcdsef");

this works every time:

char* _replace(char* source_str,char* search_str,char* replace_str)
{
char *ostr, *nstr = NULL, *pdest = "";
int length, nlen;
unsigned int nstr_allocated;
unsigned int ostr_allocated;


if(!source_str || !search_str || !replace_str){
printf("Not enough arguments\n");
return NULL;
}
ostr_allocated = sizeof(char) * (strlen(source_str)+1);
ostr = malloc( sizeof(char) * (strlen(source_str)+1));
if(!ostr){
printf("Insufficient memory available\n");
return NULL;
}
strcpy(ostr, source_str);


while(pdest)
{
pdest = strstr( ostr, search_str );
length = (int)(pdest - ostr);


if ( pdest != NULL )
{
ostr[length]='\0';
nlen = strlen(ostr)+strlen(replace_str)+strlen( strchr(ostr,0)+strlen(search_str) )+1;
if( !nstr || /* _msize( nstr ) */ nstr_allocated < sizeof(char) * nlen){
nstr_allocated = sizeof(char) * nlen;
nstr = malloc( sizeof(char) * nlen );
}
if(!nstr){
printf("Insufficient memory available\n");
return NULL;
}


strcpy(nstr, ostr);
strcat(nstr, replace_str);
strcat(nstr, strchr(ostr,0)+strlen(search_str));


if( /* _msize(ostr) */ ostr_allocated < sizeof(char)*strlen(nstr)+1 ){
ostr_allocated = sizeof(char)*strlen(nstr)+1;
ostr = malloc(sizeof(char)*strlen(nstr)+1 );
}
if(!ostr){
printf("Insufficient memory available\n");
return NULL;
}
strcpy(ostr, nstr);
}
}
if(nstr)
free(nstr);
return ostr;
}

I improved the one found here

so that is compatible with both windows-libs and gcc and g++

 
0
 

the function above have some bugs.... it fails for example with this:
replace("1.2.3.4.5.6.7.8.9",".","abcdsef");

Perhaps you could point out where?

int main(void)
{
   char *after = replace("1.2.3.4.5.6.7.8.9",".","abcdsef");
   if ( after != NULL )
   {
      printf("after  = \"%s\"\n", after);
      free(after);
   }
   return 0;
}

/* my output
after  = "1abcdsef2abcdsef3abcdsef4abcdsef5abcdsef6abcdsef7abcdsef8abcdsef9"
*/
 
-1
 

this is the simple one to replace a string . sorry put ur is too long and complicated :)

#include <stdafx.h>

#include<stdio.h>
#include<string.h>
int main
{
 char *foo = "???12?12???2"; 
 char buf[100];
 int l = strlen(foo);
int i;

 for(i=0;i<l;i++)
 {

        if(*foo=='?')
   buf[i] = ' ';
  else
   buf[i] = *foo;
        *foo++;

 }
 for(i=0;i<l;i++)
  printf("%c",buf[i]);
  printf("\n");
  getchar ();
}
 
0
 

Your code worked like a charm. (Debian, GCC 4.7)

Nonetheless, you shoud add cast to char* at lines 31 and 70 because malloc() and realloc() return argument are of type void*.

 
1
 

Nonetheless, you shoud add cast to char* at lines 31 and 70 because malloc() and realloc() return argument are of type void*.

C supports implicit conversion both to and from void*. Best practice in C is not to cast, because the cast can hide a legitimate and common error of forgetting to include <stdlib.h>. However, if your personal style is to add the cast, it won't hurt anything as long as you're careful.

In C++ or C meant to be compatible with C++, you must include the cast, because C++ doesn't allow implicit conversion from void*.

Isn't it about time forums rewarded their contributors?

Earn rewards points for helping others. Gain kudos. Cash out. Get better answers yourself.

It's as simple as contributing editorial or replying to discussions labeled or OP Kudos

You
This is an OP Kudos discussion and contributors may be rewarded
Post:
Start New Discussion
Tags Related to this Article