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

I have a text file with lines of text and a number at the end. I read the line and the number and want to now print that line to a new text file at the line determined by the number. For example, line: "Today is a good day 5". This line needs to be printed in the 5th line of the new text file. The next line after it may be: "Today is a good day 1". This line needs to be printed in the 1st line of the new text file. How do I do this? Thanks!

Replies are listed 'Best First'.
Re: Print to specific line
by toolic (Bishop) on Jun 23, 2015 at 17:22 UTC
    One approach is to grab the number, stuff all lines into a hash, then print the sorted lines. I made many assumptions about your input and output.
    use warnings; use strict; my %lines; while (<DATA>) { my ($num) = $_ =~ /(\d+)$/; $lines{$num} = $_; } for (sort {$a <=> $b} keys %lines) { print $lines{$_}; } __DATA__ foo bar 4 goo 1 hoo boo boo 2 yeah 3

    Outputs:

    goo 1 hoo boo boo 2 yeah 3 foo bar 4

      Don't think this would work as he wants if the data are as follows:

      __DATA__ foo bar 3 goo 1 hoo boo boo 5 yeah 7
        It works for me (output):
        goo 1 foo bar 3 hoo boo boo 5 yeah 7

        In what way will it not work?

        Dum Spiro Spero
Re: Print to specific line
by AnomalousMonk (Archbishop) on Jun 23, 2015 at 18:19 UTC

    Another (slightly different) way:

    c:\@Work\Perl\monks\perlUser345>perl -wMstrict -le "print map $_->[0], sort { $a->[1] <=> $b->[1] } map [ $_, extract($_) ], <> ; ;; sub extract { $_[0] =~ m{ (\d+) \s* \z }xms or die qq{bad line '$_[0]'}; return $1; } " c.txt some days are bad 0 sunny, sunny, sunny 1 but not as good as yesterday 2 tomorrow will be better 3 but maybe a few showers 4 today is a good day 5 anything can happen 11
    Where file  c.txt is:
    today is a good day 5 tomorrow will be better 3 but not as good as yesterday 2 anything can happen 11 sunny, sunny, sunny 1 but maybe a few showers 4 some days are bad 0


    Give a man a fish:  <%-(-(-(-<

Re: Print to specific line
by 1nickt (Canon) on Jun 23, 2015 at 17:41 UTC

    It would be very helpful to see the relevant part of your code. You'd get better answers faster that way, but here's what I can offer with what you've said:

    Sounds like you should build up a data structure in your program and then print the whole thing to the text file.

    Assuming, as you say, that you already have the strings and the line numbers, and you've stored them in a hash, then you want something like this:

    #!perl use strict; use warnings; use feature qw/ say /; my %hash = ( 4 => 'The future is unknown.', 1 => 'The day before yesterday sucked.', 2 => 'Yesterday was no better.', 5 => 'Today is a good day.', 3 => 'Not much hope for tomorrow.', ); my @output_lines; while (my ($number, $string) = each %hash) { $output_lines[$number] = $string; } for ( @output_lines ) { say $_; } __END__ ## Output: Use of uninitialized value $_ in say at ./foo.pl line 22. The day before yesterday sucked. Yesterday was no better. Not much hope for tomorrow. The future is unknown. Today is a good day.

    Of course this assumes that you have a line for each number, otherwise your output file will have a bunch of empty lines. You will also get a warning about an uninitialized value for $_ as the program tries to read any elements of @output_lines which are empty. For example, the first one, if you don't have a string with position zero, as seen above.

    UPDATE: Clarified the uninitialized warnings explanation.
      It seems to me that you are doing a little bit too much work. A hash AND an array are not needed, just one of them is enough.

      We can either store the lines directly into an array (indexed with the output line numbers) and just print the way you did. Or store the lines into a hash, and sort the keys for printing.

        Hm, can't agree, really. I think he needs an array because he said the line numbers are important.

        If you use a sorted hash then the output file will only contain lines for the strings he has, and if there are any sequential numbers missing from the input, then the output file will not meet the specs.

        (I do agree that you could put the data into an array as you split the input lines, skipping the hash. But I didn't want to clutter my example with code for splitting the input, as he said he has the strings and the line numbers already).

Re: Print to specific line
by kcott (Archbishop) on Jun 24, 2015 at 07:14 UTC

    G'day perlUser345,

    Welcome to the Monastery.

    Here's one way to do it:

    #!/usr/bin/env perl -l use strict; use warnings; no warnings 'uninitialized'; my @out_records; my $re = qr{ ^ ( .* ) \s ( \d+ ) $ }x; /$re/ and $out_records[$2 - 1] = $1 while <DATA>; print for @out_records; __DATA__ Line 5 5 Line 1 1 Line 3 3

    Output:

    $ pm_1131675_order_out_by_input_spec.pl Line 1 Line 3 Line 5

    -- Ken

Re: Print to specific line
by stevieb (Canon) on Jun 23, 2015 at 21:26 UTC

    I don't get to play with one-liner obfu/golf too often, so thought I'd try this question :) Prints an empty line in between any missing numbers.

    perl -le 'for(<>){/(.*?)(\d+)/;$h{$2}=$1;$a=$2if$2>$a;}for(1..$a){print$h{$_}||""}' c.txt

    Input:

    today 5 tomorrow 3 but not as 2 anything can 11 what the hell 4 I don't know 6 I'm outta here! 10
Re: Print to specific line
by GotToBTru (Prior) on Jun 23, 2015 at 18:48 UTC

    Should the numbers appear in the output?

    Dum Spiro Spero