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

I understand that tr/abc// use "abc" for matching, instead it uses "a", "b", and "c" to match $_ separately. Therefore this counting won't work correctly:
$x = 0; $cnt = tr/abc//; $x += $cnt;
I've tried:
$x = 0; while (<DATA>) { $cnt = m/abc/g; $x += $cnt; }
This won't work either... So, is there a way to find out how many times string "abc" appeared?

Could any Perl Master enlighten me a little bit?

Edit Masem 2001-07-19 - Moved question text from child node to root node.

Replies are listed 'Best First'.
Re: tr/abc// won't use string
by Sifmole (Chaplain) on Jul 19, 2001 at 22:37 UTC
Re: tr/abc// won't use string for matching, then what?
by supernewbie (Beadle) on Jul 19, 2001 at 22:11 UTC

    Editor's Note - Masem - 2001-07-19 - Please note text of original question was given below with an empty root node; this text has been copied into the root node for completeness' sake.

    I understand that tr/abc// use "abc" for matching, instead it uses "a", "b", and "c" to match $_ separately.
    Therefore this counting won't work correctly:

    $x = 0; $cnt = tr/abc//; $x += $cnt;
    I've tried:
    $x = 0; while (<DATA>) { $cnt = m/abc/g; $x += $cnt; }
    This won't work either... So, is there a way to find out how many times string "abc" appeared?

    Could any Perl Master enlighten me a little bit?

      First,

      Here's a quick hack that will work:

      my $cnt = 0; while (<DATA>) { $cnt++ while m/abc/g; } print "number of entries: $cnt\n";
      Second,

      While i'm not entirely certain on this (hopefully another monk will straighten this out if i'm wrong), the snippet you tried doesn't work because m// returns whether it matched or not, not the number of times it matches. So if there are lines that have multiple matches, you won't get the total number of matches on that line.

      Hope This Helps,
      jynx

      Update:rewrote my snippet to be more idiomatic...

      I now tried:
      $x = 0; while (<DATA>) { ++$x while($_ =~ /abc/g); }
      but it is still not counting "abc" right....
      What did I do wrong?

        at this point,

        i should have asked previously, excuse me for the delay, but it might help to know what results you're actually getting and what version of perl you're using. This may help for further debugging...

        jynx

Re: tr/abc// won't use string
by Hofmator (Curate) on Jul 20, 2001 at 16:24 UTC

    Here's a short compare in benchmark terms of the two solutions. I added a third alternative using index - which can only be used for fixed strings whereas the other solutions can also use regexes. The following code was used:

    use strict; use warnings; use Benchmark; our $cnt = 0; our $foo = q/abcdef/ x 10_000; Benchmark::cmpthese( 1000, { 'while' => sub {$cnt++ while $foo =~ /abc/g;}, 'subst' => sub {$cnt = $foo =~ s/abc/abc/g;}, 'index' => sub {my $POS = -1; $cnt++ while (($POS = index($foo,'abc',$POS+1)) > -1);}, }); # prints Benchmark: timing 1000 iterations of index, subst, while... index: 27 wallclock secs (25.09 usr + 0.02 sys = 25.11 CPU) @ 39 +.83/s (n=1000) subst: 15 wallclock secs (14.93 usr + 0.02 sys = 14.95 CPU) @ 66 +.89/s (n=1000) while: 18 wallclock secs (17.08 usr + 0.01 sys = 17.09 CPU) @ 58 +.53/s (n=1000) Rate index while subst index 39.8/s -- -32% -40% while 58.5/s 47% -- -12% subst 66.9/s 68% 14% --
    The results vary with the length of the pattern searched for. The longer the pattern, the slower the substitution solution (as it has to substitute a longer string). The index version is always slowest. For the case where there are zero occurences of the pattern, all three alternatives take approx. the same time.

    -- Hofmator