[...]
I am genuinely amazed that the Nilges version is on its fourth or so
iteration
and doesn't yet work. I won't be surprised if someone finds a boundary
condition I missed... well, actually, I'll be a little surprised, because
this
is a pretty simple algorithm. In my preemptive defense, I just woke up
less
than half an hour ago and haven't had breakfast yet.
[...]
Here is what I came up with so far:
__________________________________________________________________
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
size_t
count_sub_strings(char const* src,
char const* cmp,
size_t size)
{
char const* head = src;
size_t count = 0;
while ((head = strstr(head, cmp)))
{
++count;
head += size;
}
return count;
}
struct replace_ex
{
char* src;
char* dest;
char const* cmp;
char const* xchg;
size_t dest_size;
size_t src_size;
size_t cmp_size;
size_t xchg_size;
};
static int
replace_get_size_ex(struct replace_ex* t,
char* src,
char const* cmp,
char const* xchg);
static char*
replace_in_place_ex(struct replace_ex* t);
static char*
replace_copy_ex(struct replace_ex* t);
static char*
replace_copy(char* src,
char const* cmp,
char const* xchg);
size_t
replace_get_count_and_size_ex(struct replace_ex* t,
char* src,
char const* cmp,
char const* xchg)
{
size_t xchg_size;
size_t cmp_size = strlen(cmp);
size_t count = count_sub_strings(src, cmp, cmp_size);
t->src = src;
t->cmp = cmp;
t->xchg = xchg;
t->dest = NULL;
t->src_size = strlen(src);
t->cmp_size = cmp_size;
t->xchg_size = strlen(xchg);
cmp_size = count * t->cmp_size;
xchg_size = count * t->xchg_size;
t->dest_size = t->src_size - cmp_size + xchg_size;
return count;
}
char*
replace_in_place_ex(struct replace_ex* t)
{
char* head = t->src;
char* const tail = t->src + t->src_size;
assert(t && t->xchg_size <= t->cmp_size);
if (t->cmp_size)
{
while ((head = strstr(head, t->cmp)))
{
char* remain_tail = head + t->cmp_size;
char* remain_head = head + t->xchg_size;
size_t size = tail - remain_tail;
memcpy(head, t->xchg, t->xchg_size);
memmove(remain_head, remain_tail, size + 1);
head = remain_head;
}
}
return t->src;
}
char* replace_in_place(char* src,
char const* cmp,
char const* xchg)
{
struct replace_ex t = { NULL };
t.src = src;
t.cmp = cmp;
t.xchg = xchg;
t.src_size = strlen(src);
t.cmp_size = strlen(cmp);
t.xchg_size = strlen(xchg);
return replace_in_place_ex(&t);
}
char*
replace_copy_ex(struct replace_ex* t)
{
char* head = t->src;
char* origin_head = t->src;
char* dest_head = t->dest;
dest_head[t->dest_size] = '\0';
memset(dest_head, 'Z', t->dest_size);
while ((head = strstr(head, t->cmp)))
{
size_t size = head - origin_head;
memcpy(dest_head, origin_head, size);
dest_head += size;
memcpy(dest_head, t->xchg, t->xchg_size);
dest_head += t->xchg_size;
head += t->cmp_size;
origin_head = head;
}
if (origin_head < t->src + t->src_size)
{
size_t size = ((t->src + t->src_size) - origin_head) - 1;
assert(size);
memcpy(dest_head, origin_head,
(t->src + t->src_size) - origin_head);
}
return t->dest;
}
char*
replace_copy(char* src,
char const* cmp,
char const* xchg)
{
struct replace_ex t = { NULL };
replace_get_count_and_size_ex(&t, src, cmp, xchg);
if ((t.dest = malloc(t.dest_size + 1)))
{
replace_copy_ex(&t);
}
return t.dest;
}
char*
test_replace_and_display(char* src,
char const* cmp,
char const* xchg)
{
struct replace_ex t = { NULL };
printf("original: %s\n"
"comparand: %s\n"
"exchange: %s\n",
src,
cmp,
xchg);
if (replace_get_count_and_size_ex(&t, src, cmp, xchg))
{
if (t.dest_size <= t.src_size)
{
printf("result: %s\n"
"_______________________________________________\n",
replace_in_place_ex(&t));
t.dest = src;
}
else if ((t.dest = malloc(t.dest_size + 1)))
{
printf("allocated: %p\n"
"result: %s\n"
"_______________________________________________\n",
(void*)t.dest,
replace_copy_ex(&t));
}
}
else
{
puts("result: not found!\n"
"_______________________________________________");
t.dest = src;
}
return t.dest;
}
int
main(void)
{
char* dest1;
char* dest2;
char src[] = "XYXYX--XYXYXY--XYXYXY";
dest1 = test_replace_and_display(src, "XY", "AB");
dest2 = test_replace_and_display(dest1, "--", "<-->");
if (dest1 != src && dest1 != dest2) free(dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "--", "<-->");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "<<", "|");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, ">>", "|");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "ABABAB", "1234");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "ABABX", "ABCDEFG");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "-", "");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "||", "<<XXX>>");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "<X", "-");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, ">X", "--->");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "X>", "X--->");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "1234", "!");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "<-XX--->>!", "!");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "ABCD", "Hello");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "EFG", " World");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "!@#", "123456789");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "!!", "!");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "Hello", "Goodbye");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
dest2 = test_replace_and_display(dest1, "!", "! We are going to miss
you!");
if (dest1 != src && dest1 != dest2)
free(dest1), printf("freed: %p\n", (void*)dest1);
dest1 = dest2;
if (dest1 != src)
free(dest1), printf("freed: %p\n", (void*)dest1);
return 0;
}
__________________________________________________________________