1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
char * str_replace(char *str, char *old, char *new) { int i, count = 0; int newlen = strlen(new); int oldlen = strlen(old); for (i = 0; str[i]; ++i) if (strstr(&str[i], old) == &str[i]) ++count, i += oldlen - 1; char *ret = (char *) calloc(i + 1 + count * (newlen - oldlen), sizeof(char)); if (!ret) return; i = 0; while (*str) if (strstr(str, old) == str) strcpy(&ret[i], new), i += newlen, str += oldlen; else ret[i++] = *str++; ret[i] = '\0'; return ret; }
Refactorings
No refactoring yet !
R. Pate
June 27, 2009, June 27, 2009 06:15, permalink
My own weak first pass. (Tests included!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
#include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> void str_replace_inline(char* str, char const* old, char const* new) { assert(str); assert(new); assert(old); int const newlen = strlen(new); int const oldlen = strlen(old); assert(oldlen > 0); assert(newlen <= oldlen); char* next = str; while (*str) { if (strncmp(str, old, oldlen) == 0) { strncpy(next, new, newlen); next += newlen; str += oldlen; } else { *next++ = *str++; } } while (*str) { *next++ = *str++; } *next = '\0'; } void str_replace_malloc(char** str, int* str_size, char const* old, char const* new) { assert(str != NULL); assert(*str != NULL); assert(str_size); assert(new != NULL); assert(old != NULL); int const newlen = strlen(new); int const oldlen = strlen(old); assert(oldlen > 0); if (newlen <= oldlen) { str_replace_inline(*str, old, new); } else { for (char* i = *str; *i; ++i) { if (strncmp(i, old, oldlen) == 0) { int new_str_size = (i - *str) + newlen * 2 + 100; char* new_str = malloc(new_str_size); if (!new_str) { perror("malloc failed"); abort(); // or whatever you want } strncpy(new_str, *str, i - *str); char* next = new_str + (i - *str); strncpy(next, new, newlen); next += newlen; i += oldlen; while (*i) { if (strncmp(i, old, oldlen) == 0) { strncpy(next, new, newlen); next += newlen; i += oldlen; } else { *next++ = *i++; } if ((next - new_str) + newlen >= new_str_size) { new_str_size *= 2; new_str_size += newlen + 1; char* new_new_str = malloc(new_str_size); if (!new_new_str) { perror("malloc failed"); abort(); // or whatever you want } strncpy(new_new_str, new_str, next - new_str); next = new_new_str + (next - new_str); free(new_str); new_str = new_new_str; } } *next = '\0'; *str = new_str; *str_size = new_str_size; return; } } } } typedef struct { int id; char const* old; char const* new; char const* initial; char const* expected; } Test; int main() { Test tests[] = { {__LINE__, "a", "b", "aaaa", "bbbb"}, {__LINE__, "a", "b", "abca", "bbcb"}, {__LINE__, "aa", "b", "aaaa", "bb"}, {__LINE__, "aa", "b", "aaab", "bab"}, {__LINE__, "a", "bb", "a", "bb"}, {__LINE__, "a", "bb", "aa", "bbbb"}, {__LINE__, "old", "newish", "blah blah old blah oldold blah", "blah blah newish blah newishnewish blah"}, {__LINE__, "old", "newish", "old blah old", "newish blah newish"}, }; for (Test* i = tests; i != tests + sizeof tests / sizeof *tests; ++i) { int size = strlen(i->initial) + 1; char* buf = malloc(size); strcpy(buf, i->initial); str_replace_malloc(&buf, &size, i->old, i->new); if (strcmp(buf, i->expected) != 0) { printf("failed test %d, expected '%s', got '%s'\n", i->id, i->expected, buf); } free(buf); } }
Eric Hoffman
April 7, 2010, April 07, 2010 05:52, permalink
A recursive implementation of the above. Has a max string length limiter, trades time for memory by allocating the minimum needed each pass and a few more test cases.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> void str_replace_inline(char* str, char const* old, char const* new) { assert(str); assert(new); assert(old); int const newlen = strlen(new); int const oldlen = strlen(old); assert(oldlen > 0); assert(newlen <= oldlen); char* next = str; while (*str) { if (strncmp(str, old, oldlen) == 0) { strncpy(next, new, newlen); next += newlen; str += oldlen; } else { *next++ = *str++; } } while (*str) { *next++ = *str++; } *next = '\0'; } char* str_replace_malloc(char** str, unsigned int* str_size, char const* old, char const* new, const unsigned int maxlen) { assert(str != NULL); assert(*str != NULL); assert(str_size); assert(new != NULL); assert(old != NULL); int const newlen = strlen(new); int const oldlen = strlen(old); char* i; assert(oldlen > 0); if (newlen <= oldlen) { str_replace_inline(*str, old, new); } else { for (i = *str; *i; ++i) { if (strncmp(i, old, oldlen) == 0) { int new_str_size = *str_size + newlen - oldlen; if (maxlen && new_str_size > maxlen) //0 for no max string length return NULL; char* new_str = malloc(new_str_size); if (!new_str) { perror("malloc failed"); abort(); } strncpy(new_str, *str, i - *str); //copy before match char* next = new_str + (i - *str); strncpy(next, new, newlen); //append replacement next += newlen; i += oldlen; strncpy (next, i, *str_size-(i-*str)); //copy after match free (*str); //free old small source string *str_size = new_str_size; if (*next) //continue if not at end str_replace_malloc(&new_str,str_size,old,new,maxlen); *str = new_str; } } } return *str; } typedef struct { int id; char const* old; char const* new; char const* initial; char const* expected; } Test; int main() { Test* i; Test tests[] = { {__LINE__, "a", "b", "aaaa", "bbbb"}, {__LINE__, "a", "b", "abca", "bbcb"}, {__LINE__, "aa", "b", "aaaa", "bb"}, {__LINE__, "aa", "b", "aaab", "bab"}, {__LINE__, "aa", "a", "aaaa", "aa"}, {__LINE__, "a", "bb", "a", "bb"}, {__LINE__, "a", "bb", "aa", "bbbb"}, {__LINE__, "old", "newish", "blah blah old blah oldold blah", "blah blah newish blah newishnewish blah"}, {__LINE__, "old", "newish", "old blah old", "newish blah newish"}, {__LINE__, "a", "ba", "aa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaa"}, }; for (i = tests; i != tests + sizeof tests / sizeof *tests; ++i) { unsigned int size = strlen(i->initial) + 1; char* buf = malloc(size); strcpy(buf, i->initial); str_replace_malloc(&buf, &size, i->old, i->new, 40); if (strcmp(buf, i->expected) != 0) printf("failed test %d, expected '%s', got '%s'\n", i->id, i->expected, buf); free(buf); } return 0; }
Eric Hoffman
April 13, 2010, April 13, 2010 05:34, permalink
A second pass after using the code a bit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
char* strreplaceinline(char* str, char const* old, char const* new) { assert(str); assert(new); assert(old); char* strStart = str; unsigned int const newlen = strlen(new); unsigned int const oldlen = strlen(old); assert(oldlen > 0); assert(newlen <= oldlen); char* next = str; while (*str) { if (strncmp(str, old, oldlen) == 0) { strncpy(next, new, newlen); next += newlen; str += oldlen; } else { *next++ = *str++; } } while (*str) { *next++ = *str++; } return strStart; } #define strreplace(a,b,c,d) strreplacen(a,b,c,d,0) char* strreplacen(char* str, unsigned int* str_size, char const* old, char const* new, const unsigned int start) { assert(str != NULL); assert(str_size); assert(new != NULL); assert(old != NULL); unsigned int const newlen = strlen(new); unsigned int const oldlen = strlen(old); char* i; assert(oldlen > 0); if (newlen <= oldlen) { return strreplaceinline(str, old, new); } else { for (i = str+start; *i; ++i) { if (strncmp(i, old, oldlen) == 0) { unsigned int new_str_size = *str_size + newlen - oldlen; char* new_str = malloc(new_str_size); if (!new_str) { return NULL; } strncpy (new_str, str, i - str); //copy before match char* next = new_str + (i - str); strncpy (next, new, newlen); //append replacement next += newlen; i += oldlen; strncpy (next, i, *str_size-(i-str)); //copy after match if (start) free (str); //free old small source string *str_size = new_str_size; if (*next) //continue if not at end return strreplacen(new_str, str_size, old, new, next-new_str); return new_str; } } } return str; }
Pretty weak first pass at a character array substitution func