http://qs321.pair.com?node_id=82140


in reply to Re: Replacing a given character starting with the xth occurence in a string
in thread Replacing a given character starting with the xth occurence in a string

I can see that you put some effort in this program, so I have ++'d your post. Now I'll offer some comments as constructive criticism, and a rewriting of your program to show some more Perlish ways of doing things: So here's my first rewrite of the main section of your program:
@q = split (//, $p); foreach (@q) { $count++ if $_ eq $matchchar; if ($_ eq $matchchar && ($count >= $nummatch)) { $_ = $repchar; } } $out = join ("", @q); print "out === $out";
Restructuring the insides of the loop, we can get:
foreach (@q) { if ($_ eq $matchchar) { if (++$count >= $nummatch) { $_ = $repchar; } } }
Now compressing the two if's, we get:
foreach (@q) { if ($_ eq $matchchar && ++$count >= $nummatch) { $_ = $repchar; } }
Now, notice that we are assigning one value to $_ when a certain condition is satisfied, and another (actually leaving its old value) when it's not. So we could use the conditional operator to eliminate the if altogether:
foreach (@q) { $_ = ($_ eq $matchchar && ++$count >= $nummatch)?$repchar:$_; }
And now, notice that we are using the foreach to compute a value based on each element of @q. Ideal use of map!
@q = map { ($_ eq $matchchar && ++$count >= $nummatch)?$repchar:$_ } @q;
And now we don't need to initially asign the result of the split to @q, because all we are doing with it is passing it as argument to map, so we can do:
@q = map { ($_ eq $matchchar && ++$count >= $nummatch)?$repchar:$_ } split(//, $p);
And finally, we can eliminate @q altogether because we can pass the result of the map directly to the join:
$out = join ("", map { ($_ eq $matchchar && ++$count >= $nummatch)?$repchar:$_ } split (//, $p));
Proof that any program can be transformed to a one-liner in Perl :-)

Man that was fun :-)

--ZZamboni