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

Esteemed Monks,

In my searches of regexp and Perl, I am not finding the answer to this-- is it possible to flip the order of lines based on their matching a given pattern? What I have in mind is this-- you have a file with the follwing contents:

1. text'1' 2. text'2' 3. text'3' ...

With sed, you could reverse the order of the lines thus:

/'1'/{ h d } /'2'/G /'2'/{ h d } /'3'/G /'3'/{ h d }

and end up with the file

3.text'3' 2.text'2' 1.text'1'

Is there a similar capability with Perl? I was working earlier today on making a program interactive with vi (see my earlier question), and this is a similar thing-- I need it to do this within a "while" construction and spit out all the lines back into the file I'm editing when I'm done. Can this be done?

Thanks.

Replies are listed 'Best First'.
Re: Sed to perl conversion-- flipping lines in a file
by kvale (Monsignor) on Feb 17, 2004 at 22:04 UTC
    my @lines = <DATA>; print reverse @lines; __DATA__ 1. text'1' 2. text'2' 3. text'3'

    -Mark

      kvale,
      While this is a perfectly good solution, it may be an issue if the file in question is very large. In that case, instead of slurping the whole thing into memory it might be better to use a perl implementation of tac. If you need to manipulate the lines at all in addition to reversing them, you could always have a look at File::ReadBackwards

      For any other conversions of sed, there is always the s2p utility that ships with the core.

      Cheers - L~R

        Actually, I need it to swap lines Only if it matches a given pattern, like the sed example. I have some other lines Around the ones in the example which need to stay where they are. Where can I read more about s2p? I'm using perl on a network where they Think they've gotten rid of it-- everything I've tried so far works and compiles (when I get all the bugs fixed in my code) but I might not have everything. Thanks
Re: Sed to perl conversion-- flipping lines in a file
by Abigail-II (Bishop) on Feb 17, 2004 at 22:44 UTC
    perl would be overkill for the job. I'd use sort:
    sort -n -r <yourfile>

    Abigail

Re: Sed to perl conversion-- flipping lines in a file
by thelenm (Vicar) on Feb 17, 2004 at 22:35 UTC

    Just to be tricksy, here's another way to do it (originally by Eugene van der Pijll in the Santa Golf on the Fun With Perl list):

    #!/usr/bin/perl -p $\=$_.$\}{

    -- Mike

    --
    XML::Simpler does not require XML::Parser or a SAX parser. It does require File::Slurp.
    -- grantm, perldoc XML::Simpler

      This is very cool, Mike. I tried to modify it so that it would only flip lines that met certain conditions (like my sed example above) and went down in flames. Is there a way to get this code to Only swap lines around if the lines contain the following text: '1' or '2' or '3' and to otherwise print the lines in the original file order?

      What I really want to get to is something that will convert this highlighted text in vi editor (alas, I am so far in the dark ages my company has not even Heard of Vim, but would probably burn me at the stake for speaking of it):

      Line 1 Line 2 Line 3 flip line '1' flip line '2' flip line '3' Line 4 to: Line 1 Line 2 Line 3 flip line '3' flip line '2' flip line '1' Line 4

      Does this make more sense to anyone?

      Thanks very much for the (hopefully) gentle correction and admonishment, Monks.

Re: Sed to perl conversion-- flipping lines in a file
by dominix (Deacon) on Feb 17, 2004 at 22:36 UTC
    TIMTOWTDI,
    my @lines = <DATA>; print pop(@lines) for (0 .. @lines); __DATA__ 1. text'1' 2. text'2' 3. text'3'
    --
    dominix
Re: Sed to perl conversion-- flipping lines in a file
by jonadab (Parson) on Feb 17, 2004 at 22:47 UTC
    print map { $$_[1] } sort { $$a[0] <=> $$b[0] } map { /(\d+)/; [$1, $_] } <FILE>;

    ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print