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

I am reading from a file. Lets assume the file has 3 lines with 3 words on each line. Lets say the words on each line are the same...foo1, foo2 and foo3. Using the regex below is only grabbing 1 word per line and not all 3:
open(FILE, $file) or &error; @data = <FILE>; close(FILE); @extracted = (); foreach(@data){ if($_ =~ /.*?(foo\d+).*?/g){ push @extracted, $1; } }
I thought using the /g option grabbed ALL matches per line. What am I doing wrong? Thanks

Replies are listed 'Best First'.
Re: Regex help
by japhy (Canon) on Jul 08, 2002 at 19:22 UTC
    First, why store the entire file in an array? Why not just iterate one line at a time? Second, you ARE using a global regex, but in scalar context -- it can only return one match at a time. Your regex does more work than needed. You can remove the useless .*?'s in there. And, in this case, you won't end up needing the parentheses in the regex:
    open FILE, "< $file" or die "can't read $file: $!"; while (<FILE>) { push @extracted, /foo\d+/g; # just like /(foo\d+)/g }

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Regex help
by joealba (Hermit) on Jul 08, 2002 at 19:14 UTC
    The /g modifier makes the regexp match all matches in that line, returning a list of all the matches. If capturing parens are used, the captured pieces are returned in the list, rather than the entire match.

    Try this little bit of code:
    my @extracted = (); open(FILE, $file) or &error; while (<FILE>){ push @extracted, (/(foo\d+)/g); }
    Update: Those .*? in your match are really unnecessary since you're using the /g modifier. So, I removed them to speed things up.
    Updated again for semantics. Thanks, japhy
      The /g modifier doesn't return anything, nor does a pattern match return an array. The /g modifier makes a regex match globally, so that a pattern match in list context returns a LIST of all matches (either the match itself or the $DIGIT variables). In scalar context, you can step through the matches one at a time.

      _____________________________________________________
      Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Regex help
by DamnDirtyApe (Curate) on Jul 08, 2002 at 19:10 UTC

    Try your regex like this:

    @data = <DATA>; @extracted = (); foreach(@data){ while ($_ =~ s/(foo\d+)//) { push @extracted, $1; } } print join( ':', @extracted ), "\n" ; __DATA__ foo1 foo2 foo3 foo4 foo5 foo6 foo7 foo8 foo9

    Update:This does the same thing:

    @data = <DATA>; my @extracted = grep { /foo\d+/ } map { split } @data ; print join( ':', @extracted ), "\n" ; __DATA__ foo1 foo2 foo3 foo4 foo5 zoot6 foo6 foo7 foo8 bar1 foo9

    _______________
    D a m n D i r t y A p e
    Home Node | Email
      You are making assumptions about the poster's data. Also, there's no need to use a substitution when a simple
      while (/(foo\d+)/g) { push @ext, $1; }
      would work.

      _____________________________________________________
      Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Regex help
by TheFifthDeuce (Novice) on Jul 08, 2002 at 19:35 UTC
    !!! SCALAR !!! context! Damn I feel stupid now!LOL Thanks alot for the info folks! : )