Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I would like to replace all characters in a string with a X except the last 4 characters Eg 1234567890 Output :xxxxxx7890
  • Comment on How do I replace all characters in a string with X's except the last 4 character

Replies are listed 'Best First'.
Re: How do I replace all characters in a string with X's except the last 4 character
by jsprat (Curate) on May 02, 2002 at 20:17 UTC
    The answers above are good. However, the substr function will let you replace characters in place, saving one of the calls to substr. Here's a one-liner that does what you want

    perl -e "$_='aaaaaaaaaa'; substr($_,0,-4)='X' x (length($_) -4); print +"

    Or you could use the four argument version of substr:

    perl -e "$_='1234567890'; substr($_,0,-4, 'X' x (length($_) - 4)); pri +nt"

    Update: I added these two methods to maverick's benchmark, with the following results:

    use Benchmark; my $string = "1234567890"; timethese(-5, { 'Regexp' => sub { $string =~ s/(.*?)(....)$/("X" x length($1)). +$2/e; }, 'Regexp D&P' => sub { $string =~ s/.(?!.{0,3}$)/x/g; }, 'Substring' => sub { $string = length substr($string,0,-4). substr +($string,- 4) }, 'mysubstr' => sub { substr($string,0,-4)='X' x (length($string) - 4) + }, 'fourarg' => sub { substr($string, 0, -4, 'X' x (length($string +) - 4)) } }); Benchmark: running Regexp, Regexp D&P, Substring, fourarg, mysubstr, e +ach for at least 5 CPU seconds... Regexp: 6 wallclock secs ( 5.35 usr + 0.00 sys = 5.35 CPU) @ 40 +933.99/s (n=218915) Regexp D&P: 5 wallclock secs ( 5.18 usr + 0.00 sys = 5.18 CPU) @ 90 +739.67/s (n=469850) Substring: 6 wallclock secs ( 5.19 usr + 0.00 sys = 5.19 CPU) @ 31 +6184.66/s (n=1640366) fourarg: 6 wallclock secs ( 5.10 usr + 0.00 sys = 5.10 CPU) @ 37 +0755.39/s (n=1890111) mysubstr: 6 wallclock secs ( 5.39 usr + 0.00 sys = 5.39 CPU) @ 27 +1099.83/s (n=1460957)
    Surprisingly (to me at least), mysubstr (the first method I proposed) is slower than the original substr method.

    Update2: fixed silly error (double assignment) in mysubstr and added
    'X' x
    to the original Substr to make things even, reran benchmarks.

Re: How do I replace all characters in a string with X's except the last 4 character
by particle (Vicar) on May 02, 2002 at 19:10 UTC
    perl -e"$_='1234567890';print 'x' x length substr($_,0,-4), substr($_, +-4)"
    or, in full-program form:

    #!/usr/bin/perl -w use strict; $|++; my $string = '1234567890'; my $new_string = ( 'x' x length substr($string, 0, -4) ) . substr($str +ing, -4); print $new_string;

    ~Particle *accelerates*

s///e
by RMGir (Prior) on May 02, 2002 at 19:04 UTC
    Interesting...

    This might not be the most efficient way to do it, but you could do:

    #!/usr/bin/perl -w use strict; while(<>) { s/(.*?)(....)$/("X" x length($1)).$2/e; print; }
    The efficient way is probably:
    #!/usr/bin/perl -w use strict; while(<>) { chomp; if(length > 4) { my $tail = substr($_,-4); $_=('X'x (length($_)-4)).$tail; } print "$_\n"; }
    Of course, I could be wrong; the regex could be faster than substr. I'll defer to someone with enough tuits to run a benchmark :)
    --
    Mike

    Edit: maverick (++) had the tuits; substr wins by a large margin.

      Here's yer tuit...
      use Benchmark; my $string = "1234567890"; timethese(-5, { 'Regexp' => sub { $string =~ s/(.*?)(....)$/("X" +x length($1)).$2/e; }, 'Regexp D&P' => sub { $string =~ s/.(?!.{0,3}$)/x/g; +}, 'Substring' => sub { $string = length substr($string +,0,-4). substr($string,-4) } });
      Yields:
      Benchmark: running Regexp, Regexp D&P, Substring, each for at least 5 +CPU seconds... Regexp: 6 wallclock secs ( 5.38 usr + 0.00 sys = 5.38 CPU) @ 17 +3245.35/s (n=932060) Regexp D&P: 6 wallclock secs ( 5.30 usr + 0.00 sys = 5.30 CPU) @ 20 +0480.57/s (n=1062547) Substring: 7 wallclock secs ( 5.45 usr + 0.00 sys = 5.45 CPU) @ 10 +04355.05/s (n=5473735)
      This is on a 2 GHz Pentium 4. Let's say we increase $string to 1000 characters...
      Benchmark: running Regexp, Regexp D&P, Substring, each for at least 5 CPU seconds...
          Regexp:  6 wallclock secs ( 5.29 usr +  0.00 sys =  5.29 CPU) @ 4194.33/s (n=22188)
      Regexp D&P:  5 wallclock secs ( 5.26 usr +  0.00 sys =  5.26 CPU) @ 2068.25/s (n=10879)
       Substring:  7 wallclock secs ( 5.26 usr +  0.00 sys =  5.26 CPU) @ 1022051.33/s (n=5375990)
      
      Update: Added Dog_and_Pony's solution...
      Update 2:Fixed stupid bug in Substring code. , and . do different things...
      Update 3:abstracts spotted that my substring function has a cut and paste error (sheesh). jsprat's benchmark is accurate. The four arg substring seems to be the fastest.

      /\/\averick
      OmG! They killed tilly! You *bleep*!!

Re: How do I replace all characters in a string with X's except the last 4 character
by Dog and Pony (Priest) on May 02, 2002 at 19:25 UTC
    Just to show TIMTOWTDI, I add this:
    #!/usr/bin/perl -w use strict; $_ = '1234567890'; s/.(?!.{0,3}$)/x/g; print;
    Update: Looks like this solution lost bigtime in the benchmarks, which is no surprise. It replaces each character one by one, and each time checks if the next 1-4 characters are among the last four. Hardly effective... It is a good example on the fact that regexps are costly, and not always the best solution. :)
    You have moved into a dark place.
    It is pitch black. You are likely to be eaten by a grue.