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

Hi Monks

I am having some problems with matching across multiple lines, even using the /s modifier. I have a piece of document I need to pick up: it starts with " Start" on one line and finishes with " End" on another.

I have tried using the following bit of code:

while(<>){ if (m/ Start(.*?) End/sg) {print $1;} }
But this doesn't seem to print anything. What am I doing wrong?

Cheers,
S D

Replies are listed 'Best First'.
Re: Matching across multiple lines
by jasonk (Parson) on Jul 19, 2005 at 14:08 UTC

    You can't match across multiple lines here, because the while is reading the file one line at a time, so your regexp never sees more than one line.

    You either need to slurp the whole file in at once, or try a different approach. Personally I prefer to use the .. operator for this type of processing...

    while(<>) { if(/Start/ .. /End/) { print } }

    Or, slurp in the whole file...

    { local $/; my $input = <>; if(/ Start(.*)? End/sg) { print $1 } }

    We're not surrounded, we're in a target-rich environment!
Re: Matching across multiple lines
by davorg (Chancellor) on Jul 19, 2005 at 14:11 UTC

    Although your regex will match across multiple lines, you are only reading the file a line at a time so at any given time $_ will contain 'Start' or 'End', but not both.

    Perhaps you want to consider reading the whole file into memory and running the regex against the whole thing in one go. Or perhaps you can do something with the flipflop operator.

    while (<>) { if (/Start/ .. /End/) { # do something } }
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Matching across multiple lines
by Transient (Hermit) on Jul 19, 2005 at 14:09 UTC
    Unless you are already localizing $/, you're reading in line by line, so your $_ will never have a match in it. You either need to slurp in the entire file, or break it up in some manner so as to comprise multiple lines.
Re: Matching across multiple lines
by kwaping (Priest) on Jul 19, 2005 at 14:55 UTC
    Try this:
    my $file = '/path/to/file.txt'; open (FILE,"<$file") || die $!; read FILE, my $text, -s $file; close(FILE); print $1 if ($text =~ / Start(.*?) End/s);
      Thanks for all your replys, people

      Problem solved!

      S D

Re: Matching across multiple lines
by Anonymous Monk on Jul 19, 2005 at 14:08 UTC
    surely here the match only evaluates a line with Start and End somewhere in the text
Re: Matching across multiple lines
by graff (Chancellor) on Jul 20, 2005 at 03:42 UTC
    If every occurrence of the string " End" reliably marks the end of a record (that is, if no record ever includes " End" as part of the internal data), you could just set $/ to this string, and read just one complete "record" at a time:
    { local $/ = " End"; while (<>) { s/.* Start//; chomp; # removes $/ (" End") from end of string print; } }
Re: Matching across multiple lines
by anniyan (Monk) on Jul 19, 2005 at 14:08 UTC

    You remove that option modifier 'g'.

    Now it will work.

    update: Sorry, i didn't tested. davorg thanks.

    Regards,
    Anniyan

      You remove that option modifier 'g'.

      Now it will work.

      Did you try your solution? Why did you think it would work?

      --
      <http://www.dave.org.uk>

      "The first rule of Perl club is you do not talk about Perl club."
      -- Chip Salzenberg