S
spinoza1111
Willem wrote:
) However, I have to disappoint you: it's not really a recursive solution,
) It will always recurse exactly once. A smart compiler could inline the
) whole thing, so you get two copies of the loop, with all the if(t) checks
) removed (i.e. one with, and one without the body of that if(t) ).
)
)
) Perhaps as a new challenge one could write a truely recursive solution,
) though. I wonder if it would be possible to do it elegantly.
Without further ado: the really recursive solution:
This time, I have tested it.
(And again, to my dismay, there was one silly bug the first time 'round.)
Note: I do not recommend this function to anybody for reasons other
than academic interest. Note, for example, that the length of the
replacement is recalculated on every recursion but the first.
char *repstr(char *s, char *m, char *r, size_t tl)
{
char *t;
size_t sl = 0, ml = 0, rl;
while (s[sl]) {
if (m[ml] == 0) {
for (rl = 0; r[rl]; rl++) ;
if (t = repstr(s+sl+ml, m, r, tl+sl+rl)) {
while (rl--) { t[tl+sl+rl] = r[rl]; }
while (sl--) { t[tl+sl] = s[sl]; }
}
return t;
}
if (s[sl+ml] != m[ml]) {
sl++;
ml = 0;
} else {
ml++;
}
}
if (t = malloc(tl + sl + 1)) {
do { t[tl+sl] = s[sl]; } while (sl--);
}
return t;
}
char *replace_string(char *str, char *match, char *replace)
{
if (match[0] == 0) return 0; /* Sanity check */
return repstr(str, match, replace, 0);
}
SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
Let's see, here's the basic idea in one line of pseudo-functional
pseudo-code in a pseudo-language that supports, in addition to the
regular operators, a C-like assignment (assert t is not null), and
garbage collection, that among other things, allows us to "guard" m by
t in index(m+t, t):
replace(m, t, r) = m == "" ? "" : (substr(m, 0, (i = index(m + t, t)))
+ ((i >= 0 && i < len(m)) ? r : "") + replace(substr(m, i+len(t)), t,
r))
Let us transliterate this to a language which supports garbage
collection, C Sharp:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace replaceCSharp
{
class Program
{
static void Main(string[] args)
{ TESTER(
"1111123bbb1111123bbb11123bb11111231111112111111123",
"111123",
"ono",
"1onobbb1onobbb11123bb1ono1111112111ono");
TESTER("bbb1111123bbbbb",
"111123",
"ono",
"bbb1onobbbbb");
TESTER("a stupid error",
"stupid error",
"miracle",
"a miracle");
TESTER("a stupid error",
"stupid",
"miracle",
"a miracle error");
TESTER("the stupid error",
"the stupid error",
"a miracle",
"a miracle");
TESTER("the miracle",
"the",
"a",
"a miracle");
TESTER("a miraclsnirpKamunkle",
"snirpKamunkle",
"e",
"a miracle");
TESTER("a miraclesnirpKamunkle",
"a miracle",
"",
"snirpKamunkle");
TESTER(" a miraclesnirpKamunkle",
"a miracle",
"",
" snirpKamunkle");
TESTER(" a miraclesnirpKamunklea miraclea miracle",
"a miracle",
"",
" snirpKamunkle");
TESTER("a stupid errord",
"stupid error",
"miracle",
"a miracled");
TESTER("a stupid errod",
"stupid error",
"miracle",
"a stupid errod");
TESTER("a sstupid error",
"stupid error",
"miracle",
"a smiracle");
TESTER("a stupid errorstupid error",
"stupid error",
"miracle",
"a miraclemiracle");
TESTER("a stupid error stupiderror",
"stupid error",
"miracle",
"a miracle stupiderror");
TESTER("bbbbbbbbbb",
"b",
"a",
"aaaaaaaaaa");
TESTER("In the halls of R'yleh great %s lies dreaming",
"%s",
"Cthulu",
"In the halls of R'yleh great Cthulu lies
dreaming");
TESTER("%s%s%s%s%s%s",
"%s",
"Cthulu",
"CthuluCthuluCthuluCthuluCthuluCthulu");
TESTER("banana",
"ana",
"oat",
"boatna");
TESTER(" a stupid errorstupid errorHeystupid errors",
"stupid error",
"+",
" a ++Hey+s");
TESTER("foo barfoo barf",
"foo bar",
"bas",
"basbasf");
TESTER("abab",
"ba",
"ba",
"abab");
TESTER("abab",
"bab",
"boop",
"aboop");
TESTER("banana",
"ana",
"ono",
"bonona");
TESTER("a",
"x",
"b",
"a");
TESTER("x",
"x",
"b",
"b");
TESTER("egregious",
"egregious",
"egregious",
"egregious");
TESTER("egregious",
"egregious",
"x",
"x");
TESTER("",
"egregious",
"x",
"");
}
private static void TESTER(string m,
string t,
string r,
string e)
{
Console.WriteLine("Replace " +
"\"" + t + "\" by " +
"\"" + r + "\" in " +
"\"" + m + "\": " +
Environment.NewLine +
"expecting " + "\"" + e + "\"" +
Environment.NewLine +
" " +
"\"" +
replace(m, t, r) +
"\"");
}
static string replace(string m, string t, string r)
{
if (t == "") return "";
int i = 0;
int j = 0;
return m == ""
?
""
:
(m.Substring(0, (i = (m + t).IndexOf(t)))
+
((i >= 0 && i < m.Length) ? r : "")
+
((j = i + t.Length) >= m.Length
?
""
:
replace(m.Substring(j), t, r)));
}
}
}
This worked almost immediately for all our test cases (about 30 mn,
one bug owing to the fact that C sharp does not consider a substring
with an index beyond the end of the string to be valid).
The lesson is that recursive expressions, once inspected by
intelligent and agreeable chaps for correctness, constitute proofs of
validity which are easily transformed into reliable code, as witness
your speed at coding the recursive solution.
The objection to recursion is that the stack might get overloaded and
tromp on top of the heap if (as Schildt tells us, vividly but not in
all cases correctly, needless to say) the heap floats above the stack.
But if your machine is hardware optimized for stacks no prob.