It reports rather than counts these matches. I would never write a
function with this spec. because it destroys its usefulness in other
contexts. A function should do one thing well.
So are you talking about a separate function to count the number of
potential replacements before making them?
I've only ever seen find-replace functions report how many replacements
were actually made, after the fact.
I'd write a string match/replace function that returns the number of
matches. If I needed the counts reported by line, I'd write a wrapper
that adds those.
int replace_string(const char *match, const char *repl, int stopper,
FILE *fi, FILE *fo)
{
int nmatches = 0, c;
const char *mp = match;
while ((c = fgetc(fi)) != EOF && c != stopper)
if (c == *mp) {
if (!*++mp) {
++nmatches;
fputs(repl, fo);
}
}
else {
mp = match;
fputc(c, fo);
}
return nmatches;
}
Called with stopper == EOF it processes a whole file. Note how removing
the line buffer actually simplifies the code, whilst also removing an
unnecessary restriction. It's not uncommon for this to happen (there
was a recent thread about this).
Called with stopper == '\n' it processes a line and so this wrapper
prints the report:
void replace_string_report(const char *match, const char *repl,
FILE *fi, FILE *fo)
{
int total_matches = 0, lineno = 0;
while (!feof(fi)) {
int nm = replace_string(match, repl, '\n', fi, fo);
printf("\nLine %d: %d replacements\n", ++lineno, nm);
total_matches += nm;
}
printf("%d replacements\n", total_matches);
}
Above you said my original code "reports rather than counts these
matches." and "I would never write a function with this spec."
Maybe I'm confused, but it looks like you did exactly that. Your
program makes the replacements, then reports how many were made.
From your earlier statements, I was expecting a separate function to
count the number of matches.
Here's the driver for testing.
int main(int argc, char **argv)
{
if (argc > 2) {
FILE *fin = argc > 3 ? fopen(argv[3], "r") : stdin;
FILE *fout = argc > 4 ? fopen(argv[4], "w") : stdout;
if (fin && fout)
replace_string_report(argv[1], argv[2], fin, fout);
}
}
Functions that mix tasks that can be logically separated are best
avoided. Functions with hard-wired file names and strings are, well,
let's just say, sub-optimal. Students used to say "but it's because I'm
just testing" but a simple driver like the one above makes testing
much easier than having the files and strings hard wired.
<snip>
I definitely like the functionality in main() and the replace-string()
code, but there might be bugs:
original input data
replace 46 with ----
1: 14513111664214260256543011122553234523520226455552
2: 41602561064325541006060354620223361346535061545034
3: 63164621623130051346620535103421535300201464252314
4: 30013144611120401561305220534605456101542562311260
5: 30501506124251042546364005110661421500320026101445
6: 35355334213621124600100142264440253516210400362562
7: 65140560414014522562466550406113020500531011441421
8: 60543325410345553336424511333322104440166124450061
9: 44310321435636412163052026304311532342515351020026
10: 10536502643531635353214012163164121056142415600245
should return:
1: 14513111664214260256543011122553234523520226455552
2: 4160256106432554100606035----202233613----535061545034
3: 6316----216231300513----620535103421535300201----4252314
4: 3001314----1112040156130522053----05456101542562311260
5: 305015061242510425----364005110661421500320026101445
6: 3535533421362112----00100142264440253516210400362562
7: 65140560414014522562----6550406113020500531011441421
8: 60543325410345553336424511333322104440166124450061
9: 44310321435636412163052026304311532342515351020026
10: 10536502643531635353214012163164121056142415600245
* running your code with stopper EOF removes most occurrences of
standalone 4, but not all. Looks like repeating characters (eg 44)
aren't handled correctly, so it missed the first '46' in line 4, which
probably lead to it undercounting the replacements by one.
output:
1: 15131116621260256530111225532352352022655552
2: 1602561063255100606035----202233613----5350615503
3: 6316----216231300513----62053510321535300201----425231
4: 30013146111200156130522053----055610152562311260
5: 3050150612251025----360051106612150032002610145
6: 353553321362112----0010012264025351621000362562
7: 6510560101522562----6550061130205005310114121
8: 605332510355533362511333322104016612450061
9: 431032135636121630520263031153232515351020026
10: 10536502635316353532101216316121056121560025
* running it with EOF stopper reports all replacements were made in line 1
[dfs@home files]$ ./find_replace_BenB 46 ---- random.txt randomOut.txt
Line 1: 9 replacements
9 replacements
* running it with the '\n' stopper miscounts the lines, and removes the
line breaks.
[dfs@home files]$ ./find_replace_BenB 46 ---- random.txt randomOut.txt
Line 1: 0 replacements
Line 2: 2 replacements
Line 3: 3 replacements
Line 4: 1 replacements
Line 5: 1 replacements
Line 6: 1 replacements
Line 7: 1 replacements
Line 8: 0 replacements
Line 9: 0 replacements
Line 10: 0 replacements
Line 11: 0 replacements
9 replacements
output:
151311166212602565301112255323523520226555521602561063255100606035----202233613----53506155036316----216231300513----62053510321535300201----42523130013146111200156130522053----0556101525623112603050150612251025----360051106612150032002610145353553321362112----00100122640253516210003625626510560101522562----655006113020500531011412160533251035553336251133332210401661245006143103213563612163052026303115323251535102002610536502635316353532101216316121056121560025