C: implementing str_replace to replace all occurrences of substring
Last time, I showed how to replace PHP's str_replace in C.
//z 2013-10-19 18:04:32 IS2120@BG57IV3 T2080877905.K.F2560461818[T2,L61,R2,V7]
The previous code was only replacing one occurrence of substr which might be sufficient in most cases... but will not do the job when the pattern appears more than once within the original string.
This new piece of code will replace ALL occurrences of substring by the replacement pattern.
The following bit of code might miss some optimization, for instance we could first check how many times the pattern is found and then do only one big allocation and enter another loop to replace all patterns, but for now, this is what I came with.
//z 2013-10-19 18:04:32 IS2120@BG57IV3 T2080877905.K.F2560461818[T2,L61,R2,V7]
Maybe at a later stage I will come with another version a bit more optimized.
- /**
- * vim: tabstop=2:shiftwidth=2:softtabstop=2:expandtab
- *
- * str_replace.c implements a str_replace PHP like function
-
* Copyright (C) 2010 chantra <chantra__A__debuntu__D__org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
-
* of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
*
- * gcc -o str_replace_all str_replace_all.c
- */
-
- #include <stdio.h>
-
#include <string.h>
- #include <stdlib.h>
-
- void usage(char *p){
- fprintf(stderr, "USAGE: %s string tok replacement\n", p );
-
}
-
- char *
- str_replace ( const char *string, const char *substr, const char*replacement ){
- char *tok = NULL;
-
char
*newstr
=
NULL;
- char *oldstr = NULL;
- /* if either substr or replacement is NULL, duplicate string a let caller handle it */
- if ( substr == NULL || replacement == NULL ) return strdup (string);
- newstr = strdup (string);
-
while
(
(tok
= strstr
( newstr, substr
)
)
)
{
- oldstr = newstr;
- newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen (replacement ) + 1 );
- /*failed to alloc mem, free old string and return NULL */
- if ( newstr == NULL ){
-
free
(oldstr
);
- return NULL;
- }
- memcpy ( newstr, oldstr, tok - oldstr );
- memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ));
-
memcpy
( newstr
+
(tok
- oldstr
)
+ strlen
( replacement
), tok
+strlen
( substr
), strlen
( oldstr
)
- strlen
( substr
)
-
( tok
- oldstr
)
);
- memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen (replacement ) , 0, 1 );
- free (oldstr);
- }
- return newstr;
-
}
-
- int main( int argc, char **argv ){
- char *ns = NULL;
- if( argc != 4 ) {
-
usage
(argv
[
0
]
);
- return 1;
- }
- ns = str_replace( argv[1], argv[2], argv[3] );
- fprintf( stdout, "Old string: %s\nTok: %s\nReplacement: %s\nNew string: %s\n", argv[1], argv[2], argv[3], ns );
-
free
(ns
);
- return 0;
- }
Will output:
$ gcc -o str_replace_all str_replace_all.c
$ ./str_replace_all "(uid=%u/%u)" "%u" chantra
Old string: (uid=%u/%u)
Tok: %u
Replacement: chantra
New string: (uid=chantra/chantra)
// 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); } //z 2013-10-19 18:04:32 IS2120@BG57IV3 T2080877905.K.F2560461818[T2,L61,R2,V7]
[email protected]
String replace program in C
/**
****************************************************|
* String replace Program |
****************************************************|
* Takes three string input from the user
* Replaces all the occurances of the second string
* with the third string from the first string
* @author Swashata
*/
/** Include Libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/** Define the max char length */
#define MAX_L 4096
/** Prototypes */
voidreplace (char*, char*, char*);
intmain(void) {
charo_string[MAX_L], s_string[MAX_L], r_string[MAX_L]; //String storing variables
printf("Please enter the original string (max length %d characters): ", MAX_L);
fflush(stdin);
gets(o_string);
printf("\nPlease enter the string to search (max length %d characters): ", MAX_L);
fflush(stdin);
gets(s_string);
printf("\nPlease enter the replace string (max length %d characters): ", MAX_L);
fflush(stdin);
gets(r_string);
printf("\n\nThe Original string\n*************************************\n");
puts(o_string);
replace(o_string, s_string, r_string);
printf("\n\nThe replaced string\n*************************************\n");
puts(o_string);
return0;
}
/**
* The replace function
*
* Searches all of the occurrences using recursion
* and replaces with the given string
* @param char * o_string The original string
* @param char * s_string The string to search for
* @param char * r_string The replace string
* @return void The o_string passed is modified
*/
voidreplace(char* o_string, char* s_string, char* r_string) {
//a buffer variable to do all replace things
charbuffer[MAX_L];
//to store the pointer returned from strstr
char* ch;
//first exit condition
if(!(ch = strstr(o_string, s_string)))
return;
//copy all the content to buffer before the first occurrence of the search string
strncpy(buffer, o_string, ch-o_string);
//prepare the buffer for appending by adding a null to the end of it
buffer[ch-o_string] = 0;
//append using sprintf function
sprintf(buffer+(ch - o_string), "%s%s", r_string, ch + strlen(s_string));
//empty o_string for copying
o_string[0] = 0;
strcpy(o_string, buffer);
//pass recursively to replace other occurrences
returnreplace(o_string, s_string, r_string);
}[email protected]
//z 2013-10-19 18:04:32 IS2120@BG57IV3 T2080877905.K.F2560461818[T2,L61,R2,V7]
update on your code
FYI, your code works well as long as the thing you're replacement string doesn't include the needle value, otherwise the code is trapped in an infinite loop.
ie:
./str_replace_all foobar bar bar2
*should* have returned foobar2 but instead it gets stuck in an infinite loop building foobar2222222222222222222222222...... because the strstr() check in the while() condition starts looking at the beginning of the haystack string (or new haystack) every time, so 'bar' would get replaced with 'bar2' over and over again.
A few simple changes fixes the problem:
Line 37 adds a new pointer
Line 42 points strhead to the beginning of your new haystack string
Line 43 changes your strstr() call to use strhead
Line 44 points strhead to the token found from strstr()
Thanks for the code!