F1e3ab214a976a39cfd713bc93deb10f

Pretty weak first pass at a character array substitution func

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 !

48ccd8d56bce9ebd25c1720c13e9d442

R. Pate

June 27, 2009, June 27, 2009 06:15, permalink

No rating. Login to rate!

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

Eric Hoffman

April 7, 2010, April 07, 2010 05:52, permalink

No rating. Login to rate!

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

Eric Hoffman

April 13, 2010, April 13, 2010 05:34, permalink

No rating. Login to rate!

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

Your refactoring





Format Copy from initial code

or Cancel