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

Hi, How do I tr the second occurance of a character pair (in this case ".0") but leave the first intact? The following works, but deletes all occurances of 0, which I don't want to do.
@value[1] =~ tr/\w.0/ /d;

Replies are listed 'Best First'.
Re: Regexp: Only tr second occurance
by duff (Parson) on Jan 02, 2004 at 14:09 UTC

    Here's a way using index and substr:

    #!/usr/bin/perl my $str = "123.0456.0789.0-WHOOPS"; my $sub = ".0"; my $p = index($str,$sub,index($str,$sub)+1); print "str before = $str\n"; substr($str,$p,length($sub)) = "" unless $p < 0; print "str after = $str\n";

    Or more generally,

    #!/usr/bin/perl my $str = "123.0456.0789.0-WHOOPS"; my $sub = ".0"; print "str before = $str\n"; $str = rm_nth($str,$sub,2); print "str after = $str\n"; sub rm_nth { my ($str,$sub,$n) = @_; $n = 1 if $n < 1; my $p = -1; while ($n--) { $p = index($str,$sub,$p+1); return $str if $p < 0; } substr($str,$p,length($sub)) = ""; return $str; }

    I'm sure someone will post the generalized regular expression version now :-)

    Although, in Perl6 it will be so much nicer to say s:2nd/$pat//; or s:nth(2)/$pat//;

    Update: Slight change to the assignment of $n in rm_nth so that it handles requests for deleting negative occurrences in a non-infinite-loop sort of manner :)

Re: Regexp: Only tr second occurance
by Aristotle (Chancellor) on Jan 02, 2004 at 14:55 UTC
    sub delete_nth_occurence { my ($rx, $str, $n) = @_; my @piece = split /($rx)/, $str, $n + 1; splice @piece, -2, 1 if @piece > 2; return join '', @piece; } print delete_nth_occurence(qr/\.0/, '123.0456.0789.0', 2);

    Makeshifts last the longest.

Re: Regexp: Only tr second occurance
by Aristotle (Chancellor) on Jan 02, 2004 at 14:38 UTC
    $_ = '123.0456.0789.0'; /\.0/g && /\.0/g && substr $_, $-[0], $+[0] - $-[0], "";

    Makeshifts last the longest.

Re: Regexp: Only tr second occurance
by Abigail-II (Bishop) on Jan 02, 2004 at 11:42 UTC
    Your question isn't clear at all. tr changes or deletes characters. Not character pairs, or longer sequences. \w doesn't have a special meaning in tr (unlike with regexes).

    Could you describe what you want?

    Abigail

      I want to delete the second occurance of the string ".0" in a string.
        There are several ways of doing that. One is:
        {my $i = 0; s/(\.0)/++ $i == 2 ? "" : $1/eg; }

        Abigail

Re: Regexp: Only tr second occurance
by davido (Cardinal) on Jan 02, 2004 at 16:46 UTC
    I haven't seen this one yet...

    Delete nth occurrence of .0:

    my $n = 2; my $pattern = qr/\.0/; my $string = "This is the .0 test .0 string .0"; $string = delete_nth( $string, $pattern, $n ); print $string, "\n"; sub delete_nth { my ( $str, $pat, $n ) = @_; $n--; $str =~ s/($pat.*?){$n}($pat)/$1/; return $str; }

    I tested it with a few simple test strings. One thing to note is that it won't work if $n == 1. But for any value of $n >= 2, it's fine.


    Dave

      That's easy to get around:
      sub delete_nth { my ( $str, $pat, $n ) = @_; my $cap = "$pat.*" x ( $n - 1 ); $str =~ s/($cap)$pat/$1/; return $str; }

      Makeshifts last the longest.

Re: Regexp: Only tr second occurance
by Taulmarill (Deacon) on Jan 02, 2004 at 13:02 UTC
    here´s another
    perl -e'$test="123.0456.0789";$test =~ s/(\.0.*)(.0)/$1/;print "$test\ +n";' ___output___ 123.0456789

    a bit easyer to understand than Abigails, i think.

      Easier to understand perhaps but your claim might be more justified if it actually worked properly.

      $test="123.0456.0789.0-WHOOPS"; $test =~ s/(\.0.*)(.0)/$1/; print "$test\n"; __DATA__ 123.0456.0789-WHOOPS

      you want a .*? ie

      $test =~ s/(\.0.*?)\.0/$1/s;
      will work. You also need a \. on the second .0 so it does not match the wrong stuff ie 00 and you don't need to capture into $2 as you are just going to delete that part....Finally if the string can have newlines in it you need the /s modifier which will not hurt anyway. Now it may or may not be as readable as Abigail-IIs example but should be approximitely as robust.

      cheers

      tachyon