There are three distinct cases. |p| < |np|, |p| == |np|, |p| > |np|.
So your first step is to determine which of those three cases you are
in, and then perform the operation with custom code for each.
The |p| == |np| is trivial. Just search for occurrences of p, and
directly overwrite it with |np|.
The case where |p| > |np| is also fairly straightfoward. You have a
read pointer and write pointer, both of which are initialized to each
other. You copy and increment step by step, except when you notice an
occurrence of p. Then you copy over np in its place, then increment
the write pointer by |np|, and the read pointer by |p| and continue in
a loop.
The case where |p| < |np| is the really tricky one because you have to
perform an insert as you go, but you can't tell the amount of total
inserting you will need to do until you have completely scanned the
string. So the easiest way to do it, is to do it in two passes. In
the first pass you simply count up the number of occurrences of p, and
compute len, the length of p. You then compute the amount that the
string grows (len * (|np| - |p|)) and in a second pass going backwards
from the end you copy the string in segment chunks until you encounter
p, then you overwrite it with np, etc.
If you want to see an example of a very similar look at the function
bFindAndReplace() in "The Better String Library":
http://bstring.sf.net/
You make things too complicated.
/**********************************************************************/
/* File Name: replace.c. */
/* Author: Stan Milam. */
/* Date Written: 13-Jan-2003. */
/* Description: */
/* Implement a function replace all occurances of a pattern. */
/* */
/* (c) Copyright 2005 by Stan Milam. */
/* All rights reserved. */
/* */
/**********************************************************************/
#include <errno.h>
#include <string.h>
#include <stddef.h>
**********************************************************************/
/* Name: */
/* replace(). */
/* */
/* Synopsis: */
/* #include "strtools.h" */
/* char *replace(char *target, const char *from, char *to */
/* */
/* Description: */
/* The replace function will replace all instances of the from */
/* pattern with that of the to pattern. If the to pattern is */
/* an empty string or NULL all instances of the from pattern will */
/* be removed from the target string. */
/* */
/* Note: */
/* Since a replacement pattern can be longer the the original */
/* pattern the programmer must allow for enough memory to */
/* accomodate a larger target string to allow successful */
/* completion of the operation. */
/* */
/* Arguments: */
/* char *target - The string in which patterns will be */
/* replaced. Cannot be NULL */
/* */
/* const char *from - The pattern to be replaced. Cannot be NULL */
/* or an empty string (i.e. ""). */
/* */
/* const char *to - The replacement pattern. Using a NULL */
/* pointer will be interpreted the same as an */
/* empty string (i.e. ""). */
/* */
/* Return Value: */
/* In all cases the address of the target string. Should either */
/* the target string or the from pattern be NULL the global errno */
/* variable will be set to EINVAL. */
/* */
/**********************************************************************/
char *
replace ( char *p_target, const char *p_from, const char *p_to )
{
size_t to_len, from_len;
char *l_to, *ptr, *rv = p_target;
/******************************************************************/
/* Check for excrement passed in as arguments! */
/******************************************************************/
if ( p_target == NULL || p_from == NULL || *p_from == '\0' )
errno = EINVAL;
else {
/**************************************************************/
/* I should not have to do this but some compilers complain */
/* when I try to assign the empty pointer to p_to. p_to */
/* points to a string of const characters. I should be able */
/* to change the pointer! */
/**************************************************************/
l_to = p_to == NULL ? "" : (char *) p_to;
/**************************************************************/
/* Get the lengths before we enter the loop. */
/**************************************************************/
to_len = strlen( l_to );
from_len = strlen( p_from );
for(ptr = strstr(p_target,p_from); ptr; ptr = strstr(ptr,
p_from)) {
/**********************************************************/
/* We must either shrink out the replaced pattern or make */
/* room for the new pattern. If the two patterns are of */
/* equal length we don't care. */
/**********************************************************/
if ( to_len != from_len )
memmove(ptr + to_len,ptr + from_len,strlen(ptr +
from_len)+1);
/**********************************************************/
/* Once everthing is adjusted all we have to do is */
/* replace
. */
/**********************************************************/
memmove( ptr, l_to, to_len );
/**********************************************************/
/* Bump the pointer by the length of the replacement */
/* pattern just to be safe. */
/**********************************************************/
ptr += to_len;
}
}
return rv;
}
Regards,
Stan Milam.