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

Hello, I am merely trying to get the number of times a character labeled as $search appears in a series of different hash values.
Instead, I get the number of values which contain at least one $search.
I.E, PERL stops searching once it has found at least one instance of the $search inside the hash value. How can I cound the total amount of $search strings found in every hash key?
while (my ($key,$value) = each(%no)) { if ($value =~/$search/gi) { $contains++; } }
Each hash value is a long sequence of about 300 characters. If I search for a common letter, I will get $contains to equal to number of hash sequences instead of the true number of characters in the collection of values. Thanks!

Replies are listed 'Best First'.
Re: Simple (probably)
by ikegami (Patriarch) on Dec 13, 2009 at 04:49 UTC

    For each hash element, you execute

    if ($value =~ /$search/gi) { $contains++; }

    $contains++ isn't in any kind of loop, so it gets executed at most once. So let's add the loop we need:

    while ($value =~ /$search/gi) { $contains++; }

    This is equivalent, yet simpler and faster:

    ++contains while $value =~ /$search/gi;

    And this is faster yet (assuming $search contains no captures):

    $contains += () = /$search/gi;

    By the way, using m//g in scalar context outside of while condition is a bug.* This includes using it as an if condition.

    * — Yes, this is a generalisation, but it's accurate for those don't know what makes the statement incomplete.

      I appreciate your explanations. Very succinct teacher. Kind of unrelated, but what are captures?
      & What do you mean that m//g is a bug? I am quite a newbie...Thanks!
      -Eric

        what are captures?

        The parens in
        if ('foo 123 bar' =~ /(\d+)/) { print("$1\n"); }
        123

        What do you mean that m//g is a bug?

        for (1..2) { if ('ab' =~ /a/g) { print("match\n"); } else { print("no match\n"); } }
        match no match
        for (1..2) { if ('ab' =~ /a/) { print("match\n"); } else { print("no match\n"); } }
        match match
Re: Simple (probably)
by FalseVinylShrub (Chaplain) on Dec 13, 2009 at 04:44 UTC

    Hi

    How about this:

    while (my ($key,$value) = each(%no)) { $contains++ while $value =~ /$search/gi; }

    There's probably a better way, but that seems to work.

    HTH, FalseVinylShrub

    Disclaimer: Please review and test code, and use at your own risk... If I answer a question, I would like to hear if and how you solved your problem.

      Brilliant! Thank you. It worked straight off. I hadn't realized that IF wasn't executing what I needed and that I required "while"