119

Given a (char *) string, I want to find all occurrences of a substring and replace them with an alternate string. I do not see any simple function that achieves this in <string.h>.

21 Answers21

116

The optimizer should eliminate most of the local variables. The tmp pointer is there to make sure strcpy doesn't have to walk the string to find the null. tmp points to the end of result after each call. (See Shlemiel the painter's algorithm for why strcpy can be annoying.)

// 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;
}
Gaurang Tandon
  • 6,504
  • 11
  • 47
  • 84
jmucchiello
  • 18,754
  • 7
  • 41
  • 61
  • @jmucchiello: use `size_t` instead of `int` for arbitrary object/string sizes and indices into them. Also, what's the purpose of `strcpy(tmp, orig);` at the very end? It seems wrong. – Alexey Frunze Dec 01 '11 at 14:18
  • @Alex, the last strcpy(tmp,orig) copies the last part of string to the destination. Eg: replace("abab","a","c") at the end of the loop, result contains, "cbc" and orig points to the last "b" in "abab". The last strcpy appends the "b" so the returned string is "cbcb". If there is nothing left to copy, orig should be pointing to the ASCIIZ of the input string. – jmucchiello Dec 04 '11 at 00:07
  • simplification: you can replace that first `for` loop with `for (count = 1; ins = strstr(ins + rep_len, rep); ++count) {}`, then `tmp` is only used for writing. – rampion Mar 09 '13 at 01:28
  • REPLACE("abcdefghijkl", "bc","yz") Your simplification starts its search at the "cdefghijkl", not finding the bc that starts at orig+1. Your simplification also assumes there will be a match. You can't skip the ins+=rep_len. I suppose tmp isn't required and it could be written this way: for (count=0; ins = strstr(ins,rep); ++count) {ins+=rep_len;} – jmucchiello Mar 09 '13 at 02:52
  • hi, so how do i call this function? – Cmag May 15 '13 at 21:13
  • 1
    char *done = replace("abcdefghijkl", "bc", "yz"); do_stuff(); free(done); – jmucchiello May 16 '13 at 19:23
  • 2
    Be warned that this function returns NULL if there are no occurrences to replace ( if (!(ins = strstr(orig, rep))) return NULL; ). You cannot just use the output, you need to check if the output is NULL and if so use the original string (don't just copy the pointer to the result string because free(result) then frees the original string). Usage is more straightforward if the input string is just copied into the output string if there is nothing to replace. – Adversus May 17 '13 at 16:35
  • @Adversus: You can easily change that behavior by eliminating the 3rd sanity check if statement in the function. In fact that's probably worth doing no matter what. So I'll edit it now. I've just edited it. Thanks for pointing out a shortcoming of the code. – jmucchiello May 18 '13 at 16:27
  • hey! isn't there a "ins = orig;" missing before the first for loop? – roegi Nov 26 '13 at 09:30
  • @roegi Yep, I suppose so. I've added it. – jmucchiello Dec 04 '13 at 23:10
  • You really should use size_t or ptrdiff_t, not a plain int. And check for overflows, "(len_with - len_rep) * count" can become a overflow, when with is longer than rep. (A single string of "only" 64KiB (if you use the same string for orig and with) can result in a string of 4GiB) – 12431234123412341234123 Aug 23 '16 at 16:09
  • @12431234123412341234123: It is a 7 years old question and reflects 7 years old sensibilities. (And checking for int overflow is a lot easier than checking for unsigned overflow. I might add that sometime.) – jmucchiello Oct 20 '16 at 08:07
  • Hey, I just noticed a bug myself. An empty rep string causes an infinite loop. – jmucchiello Oct 20 '16 at 08:08
  • @jmucchiello : Check for a signed overflow is harder, since i signed overflow is UB, unsigned overflow is not UB. you can check unsigned overflow with `b && (a*b)/b!=a` – 12431234123412341234123 Nov 02 '16 at 14:51
  • (len_with - len_rep) can be negative. That's why they are signed. – jmucchiello Dec 08 '16 at 23:36
  • Added a rejected fix from user3193623. The first if had an && instead of ||. A NULL orig is a non-starter for this algorithm. A NULL rep is a non-starter as well. They do not both have to be NULL. Just one of them and we have to abort. – jmucchiello Dec 29 '16 at 18:32
  • Severity Code Description Project File Line Suppression State Error (active) E0513 a value of type "void *" cannot be assigned to an entity of type "char *" appscanner_plugin c:\Users\blusc\source\repos\appscanner_plugin\plugin.cpp 346 – Bluscream Dec 02 '17 at 01:37
  • @Bluescream, this is a C question. Do no use a C++ compiler to test C code. Rename your file plugin.c or set the "c mode" switch in your compiler and try again. – jmucchiello Feb 07 '18 at 22:29
  • It's year later, but I'm using this function for a small program and I noticed that it's always returning a new string. If you add `if(0 == count) { return NULL; }` right after the `for` loop, you'll skip a lot of useless work when there are no replacements to be done. – Christopher Schultz May 05 '23 at 19:41
  • @ChristopherSchultz. Interesting. Probably works if you put it just before the malloc. Not sure I should edit this function at this late date. NULL returns here normally mean something is wrong with the arguments or malloc failed. "Nothing to do" returning NULL is a bit questionable. – jmucchiello May 06 '23 at 20:35
  • Oh, it wasn't entirely clear to me that you had intended to always copy the string. That's also interesting to me. :) I guess the caller could check `errno`. I'm using this immediately before a call to `exec || exit` so I don't care either way! – Christopher Schultz May 09 '23 at 14:35
21

This is not provided in the standard C library because, given only a char* you can't increase the memory allocated to the string if the replacement string is longer than the string being replaced.

You can do this using std::string more easily, but even there, no single function will do it for you.

Don Neufeld
  • 22,720
  • 11
  • 51
  • 50
  • 23
    This question is about C, not C++. – Geremia Aug 08 '16 at 16:53
  • 1
    1/ strlen(char*)+1 is not necessarily equal of storage size. 2/ There are a lot of N versions of string functions that receive and additional buffer size parameter so there is no reason why couldn't there be an snreplace(). 3/ there could be an in-place replace and not in-place replace function. 4/ how do you think sprintf works? It's given a char* argument and it's doesn't need to increase memory allocation of it, so no reason a replace couldn't work too... (though C has a bad "string" design, and buffer size always should be passed with the pointer => snprintf) – Steven Spark Mar 12 '19 at 17:43
14

There isn't one.

You'd need to roll your own using something like strstr and strcat or strcpy.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
13

You could build your own replace function using strstr to find the substrings and strncpy to copy in parts to a new buffer.

Unless what you want to replace_with is the same length as what you you want to replace, then it's probably best to use a new buffer to copy the new string to.

Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • Re: "Unless what you want to replace_with is the same length as what you you want to replace", here's a related Q/A focused on that special case: https://stackoverflow.com/a/76592815/2103990 – Felipe G. Nievinski Jul 05 '23 at 05:39
11

Here's some sample code that does it.

#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;
}
rampion
  • 87,131
  • 49
  • 199
  • 315
  • It works, but its a bit buggy, but thanks anyways! :D here is one i found that works very well, http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring cheers! :) – Joe DF May 28 '13 at 01:39
10

As strings in C can not dynamically grow inplace substitution will generally not work. Therefore you need to allocate space for a new string that has enough room for your substitution and then copy the parts from the original plus the substitution into the new string. To copy the parts you would use strncpy.

lothar
  • 19,853
  • 5
  • 45
  • 59
  • The buffer size could be larger than the strlen, the replacement string could be smaller than the replaced string... therefore you don't need to allocate memory to perform replace. (Also on microcontrollers you might not have infinite memory, and you might need to perform replace in place. Copy everything to a new buffer might not be the right solution for everyone...) – Steven Spark Mar 12 '19 at 17:49
5
// 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

The repl_str() function on creativeandcritical.net is fast and reliable. Also included on that page is a wide string variant, repl_wcs(), which can be used with Unicode strings including those encoded in UTF-8, through helper functions - demo code is linked from the page. Belated full disclosure: I am the author of that page and the functions on it.

Laird
  • 148
  • 6
  • 3
    fast and reliable, but has a huge memory leak. – MightyPork Mar 22 '14 at 19:38
  • 3
    I don't see how it could. There's only one malloc and the caller is instructed to free the memory when it's no longer required. Could you be more specific? – Laird Mar 22 '14 at 23:02
  • @Laird `pos_cache = realloc(pos_cache` – Petr Skocik Sep 03 '16 at 13:57
  • @PSkocik The function has been upgraded since the complaint by @MightyPork but even though it now has that additional malloc/realloc for pos_cache, I can't see a code path that avoids the `free(pos_cache);` at function end. – Laird Sep 04 '16 at 04:44
  • 1
    @Laird `realloc` may fail. If it does, it returns `NULL` and leaves the old pointer intact. `p = realloc(p, x)` will, on failure, rewrite a valid heap pointer `p` with `NULL`, and if that `p` was your only reference to that heap object, you've now leaked it. It's a classic newbie mistake. – Petr Skocik Sep 04 '16 at 07:37
  • Right you are, @PSocik, I'd forgotten about that. Kudos, fixed now. Thanks for the heads-up, and please let me know if you spot any other bugs. – Laird Sep 10 '16 at 04:29
3

Here is the one that I created based on these requirements:

  1. Replace the pattern regardless of whether is was long or shorter.

  2. Not use any malloc (explicit or implicit) to intrinsically avoid memory leaks.

  3. Replace any number of occurrences of pattern.

  4. Tolerate the replace string having a substring equal to the search string.

  5. Does not have to check that the Line array is sufficient in size to hold the replacement. e.g. This does not work unless the caller knows that line is of sufficient size to hold the new string.

  6. avoid use of strcat() to avoid overhead of scanning the entire string to append another string.

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

Any suggestions for improving this code are cheerfully accepted. Just post the comment and I will test it.

Be Kind To New Users
  • 9,672
  • 13
  • 78
  • 125
2

i find most of the proposed functions hard to understand - so i came up with this:

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

output must be free'd

Gaurang Tandon
  • 6,504
  • 11
  • 47
  • 84
yogo1212
  • 93
  • 5
2
/* replace character in a string */
char* replace_char(char* str, char in, char out) {
    char * p = str;

    while(p != '\0') {
        if(*p == in)
            *p == out;
        ++p;
    }

    return str;
}
1

a fix to fann95's response, using in-place modification of the string, and assuming the buffer pointed to by line is large enough to hold the resulting string.

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);
}
byron
  • 11
  • 2
1

You can use this function (the comments explain how it works):

void strreplace(char *string, const char *find, const char *replaceWith){
    if(strstr(string, find) != 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
    }
}
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
1

This function only works if ur string has extra space for new length

void replace_str(char *str,char *org,char *rep)
{
    char *ToRep = strstr(str,org);
    char *Rest = (char*)malloc(strlen(ToRep));
    strcpy(Rest,((ToRep)+strlen(org)));

    strcpy(ToRep,rep);
    strcat(ToRep,Rest);

    free(Rest);
}

This only replaces First occurrence

1

Here goes mine, make them all char*, which makes calling easier...

char *strrpc(char *str,char *oldstr,char *newstr){
    char bstr[strlen(str)];
    memset(bstr,0,sizeof(bstr));
    int i;
    for(i = 0;i < strlen(str);i++){
        if(!strncmp(str+i,oldstr,strlen(oldstr))){
            strcat(bstr,newstr);
            i += strlen(oldstr) - 1;
        }else{
                strncat(bstr,str + i,1);
            }
    }

    strcpy(str,bstr);
    return str;
}
LinconFive
  • 1,718
  • 1
  • 19
  • 24
1

You can use strrep()

char* strrep    (   const char *    cadena,
        const char *    strf,
        const char *    strr 
    )

strrep (String Replace). Replaces strf with strr in cadena and returns the new string. You need to free the returned string in your code after using strrep.

Parameters:

  • cadena: The string with the text.
  • strf: The text to find.
  • strr: The replacement text.

Returns The text updated wit the replacement.

Project can be found at https://github.com/ipserc/strrep

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
ipserc
  • 29
  • 1
1

There is a function in string.h but it works with char [] not char* but again it outputs a char* and not a char []

It is simple and beautiful

Supposing we want to replace 'and' in 'TheandQuickandBrownandFox'.

We first split with strtok and then join with snprintf defined in the stdio.h

char sometext[] = "TheandQuickandBrownandFox";
char* replaced = malloc(1024);

// split on the substring, here I am using (and)
char* token = strtok(sometext, "and");

snprintf(replaced, 1, "%s", "");  // initialise so we can compare

while(token) {
    if (strcmp(replaced, "") < 1) {
        // if it is the first one
        snprintf(replaced, 1024, "%s", token);
        token = NULL;

    } else {
        // put the space between the existing and new
        snprintf(replaced, 1024, "%s %s", replaced, token);
        token = NULL;
    }
}

free(replaced);

This should give us:

The Quick Brown Fox

surge10
  • 622
  • 6
  • 18
0
char *replace(const char*instring, const char *old_part, const char *new_part)
{

#ifndef EXPECTED_REPLACEMENTS
    #define EXPECTED_REPLACEMENTS 100
#endif

    if(!instring || !old_part || !new_part)
    {
        return (char*)NULL;
    }

    size_t instring_len=strlen(instring);
    size_t new_len=strlen(new_part);
    size_t old_len=strlen(old_part);
    if(instring_len<old_len || old_len==0)
    {
        return (char*)NULL;
    }

    const char *in=instring;
    const char *found=NULL;
    size_t count=0;
    size_t out=0;
    size_t ax=0;
    char *outstring=NULL;

    if(new_len> old_len )
    {
        size_t Diff=EXPECTED_REPLACEMENTS*(new_len-old_len);
        size_t outstring_len=instring_len + Diff;
        outstring =(char*) malloc(outstring_len); 
        if(!outstring){
            return (char*)NULL;
        }
        while((found = strstr(in, old_part))!=NULL)
        {
            if(count==EXPECTED_REPLACEMENTS)
            {
                outstring_len+=Diff;
                if((outstring=realloc(outstring,outstring_len))==NULL)
                {
                     return (char*)NULL;
                }
                count=0;
            }
            ax=found-in;
            strncpy(outstring+out,in,ax);
            out+=ax;
            strncpy(outstring+out,new_part,new_len);
            out+=new_len;
            in=found+old_len;
            count++;
        }
    }
    else
    {
        outstring =(char*) malloc(instring_len);
        if(!outstring){
            return (char*)NULL;
        }
        while((found = strstr(in, old_part))!=NULL)
        {
            ax=found-in;
            strncpy(outstring+out,in,ax);
            out+=ax;
            strncpy(outstring+out,new_part,new_len);
            out+=new_len;
            in=found+old_len;
        }
    }
    ax=(instring+instring_len)-in;
    strncpy(outstring+out,in,ax);
    out+=ax;
    outstring[out]='\0';

    return outstring;
}
fann95
  • 1
  • 1
0

There you go....this is the function to replace every occurance of char x with char y within character string 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'; -> we do not need this
    return str;
}

An example usage could be

  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.

The function is from a string library I maintain on Github, you are more than welcome to have a look at other available functions or even contribute to the code :)

https://github.com/fnoyanisi/zString

EDIT: @siride is right, the function above replaces chars only. Just wrote this one, which replaces character strings.

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

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

And below is the output

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'
fnisi
  • 1,181
  • 1
  • 14
  • 24
0
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;
}
0

Using only strlen from string.h

sorry for my English

char * str_replace(char * text,char * rep, char * repw){//text -> to replace in it | rep -> replace | repw -> replace with
    int replen = strlen(rep),repwlen = strlen(repw),count;//some constant variables
    for(int i=0;i<strlen(text);i++){//search for the first character from rep in text
        if(text[i] == rep[0]){//if it found it
            count = 1;//start searching from the next character to avoid repetition
            for(int j=1;j<replen;j++){
                if(text[i+j] == rep[j]){//see if the next character in text is the same as the next in the rep if not break
                    count++;
                }else{
                    break;
                }
            }
            if(count == replen){//if count equals to the lenght of the rep then we found the word that we want to replace in the text
                if(replen < repwlen){
                    for(int l = strlen(text);l>i;l--){//cuz repwlen greater than replen we need to shift characters to the right to make space for the replacement to fit
                        text[l+repwlen-replen] = text[l];//shift by repwlen-replen
                    }
                }
                if(replen > repwlen){
                    for(int l=i+replen-repwlen;l<strlen(text);l++){//cuz replen greater than repwlen we need to shift the characters to the left
                        text[l-(replen-repwlen)] = text[l];//shift by replen-repwlen
                    }
                    text[strlen(text)-(replen-repwlen)] = '\0';//get rid of the last unwanted characters
                }
                for(int l=0;l<repwlen;l++){//replace rep with repwlen
                    text[i+l] = repw[l];
                }
                if(replen != repwlen){
                    i+=repwlen-1;//pass to the next character | try text "y" ,rep "y",repw "yy" without this line to understand
                }
            }
        }
    }
    return text;
}

if you want strlen code to avoid calling string.h

int strlen(char * string){//use this code to avoid calling string.h
    int lenght = 0;
    while(string[lenght] != '\0'){
        lenght++;
    }
    return lenght;
}
Salmy
  • 47
  • 4