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

dear Monks A newbie question: I have a script that modifies files in a dir. Now I would like to sort lines within each of those files in ascending numerical. Each line contains something like the follwing:
t=1920
I would like to order the lines by this content. My script reads thus:
#!/usr/bin/perl -i.bak -w use strict; ####Script to perform Inline editing of files##### ####Creates a .bak file with the contents of original file### my$dir='testSNL'; my@files; opendir(DIR, $dir) or die "Can't Open DIR\n"; while(my$file=readdir DIR){ push @files, "$dir/$file" unless -d "$dir/$file"; } closedir DIR; { local @ARGV=@files; while(<>){ s/A t=\d*/A/g; 't=\d*' <=>'t=\d*'; print } }
I get an error saying t=\\d* isnt numeric, Im doing something stupid, what? Thanks for any help Jm

Replies are listed 'Best First'.
Re: sorting numbers
by Ovid (Cardinal) on Apr 10, 2002 at 23:11 UTC

    You have some issues. First, if you read the files form @ARGV, unless I am mistaken, you won't be able to tell when one file ends and another one starts. Do you really want to create something that sorts large groups of files together? If the files are relatively small, and if I read your requirements correctly, you could try something like the following (untested).

    foreach my $file ( @files ) { local *FH; open FH, "+< $file" or die "Cannot open $file for updating: $!"; my @data = <FH>; @data = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, get_num( $_ ) ] } @data; seek FH, 0, 0 or die "Cannot seek to start of $file: $!"; print FH @data; close FH; } sub get_num { my $line = shift; my ($num)= $line =~ /t=(\d*)/; # you may need to play with this $num ||= 0; # assign a default to supress "not numeric" errors return $num; }

    What that does: for each file, open in update mode. Read the lines. Sort them with the Schwartzian Transform. seek to beginning of file, print the lines, close the file and move on to the next. I didn't call truncate as file lengths should be the same.

    Warning: As this is untested and I don't know if this really meets your needs, be sure to back up your files first. Also, take off the -i switch with this technique.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: sorting numbers
by stephen (Priest) on Apr 10, 2002 at 23:04 UTC
    A few things to get you going.

    First, to pull the 't=' numbers out of the file, you need to use backreferences. That's when you put something in parens in a regular expression, like so:

    m/A t=(d*)/; my $t_val = $1;
    If $_ were
    hello A t=40a30
    then $t_val would be 40.

    Next, you need to use sort. sort operates on a list, like so:

    my @list = ('my', 'bonnie', 'lies'); foreach my $word (sort @list) { print $word, "\n"; }
    The result is:
    bonnie lies my

    sort normally sorts alphabetically. To sort numerically, see the perlfunc:sort manual page.

    To collect all of these numbers into a list, you'll need push. Now all you need to do is put these pieces together. :)

    stephen

Re: sorting numbers
by vladb (Vicar) on Apr 10, 2002 at 23:04 UTC
    With perl, there's a number of way you could do this. One obvious solution is to read each line from the file save it into a hash were key would be the t=NUMBER (without the 't=' part :) and the value is the line itself. Then you could do a simple sort by hash keys prior to writing hash values out into a destination file.

    The hash may look something like this
    %file_stuff = ( .... 100 => 'a line of text from the file', 132 => 'another line of text', ... );
    for a file containing this data:
    ... t=100 a line of text from the file t=132 another line of text ...


    Another way could be create an array of adequate size to accomodate all lines from your file and simply enter each line in specific spot in the array based on the t= value. (say if you've got t=10 then save the file text line in array position 10, like $file_data[9]=$file_line).

    Sorry I don't have the time to write up the code... I hope you'll find it more enjoying to write the code yourself based on the hints provided here ;).

    Of course, you could always use the old good 'sort' system command to sort the file without having to resort to Perl. ;-)

    "There is no system but GNU, and Linux is one of its kernels." -- Confession of Faith