1

I am new to Perl and am trying to extract specific data from a file, which looks like this:

 Print of   9 heaviest strained elements:    


   Element no   Max strain 
      20004         9.6 % 
      20013         0.5 % 
      11189         0.1 % 
      20207         0.1 % 
      11157         0.1 % 
      11183         0.0 % 
      10665         0.0 % 
      20182         0.0 % 
      11160         0.0 % 


 ==================================================

I would like to extract the element numbers only (20004, 20013 etc.) and write these to a new file. The reading of the file should end as soon as the line (=========) is reached, as there are more element numbers with the same heading later on in the file. Hope that makes sense. Any advice much appreciated!

I now have this code, which gives me a list of the numbers, maximum 10 in a row:

my $StrainOut = "PFP_elem"."_$loadComb"."_"."$i";
open DATAOUT, ">$StrainOut" or die "can't open $StrainOut";  # Open the file for writing.

open my $in, '<', "$POSTout" or die "Unable to open file: $!\n";
my $count = 0;

 while(my $line = <$in>) {
  last if $line =~ / ={10}\s*/;
  if ($line =~ /% *$/) {
    my @columns = split "         ", $line;
    $count++;
    if($count % 10 == 0) {
      print DATAOUT "$columns[1]\n";
    }
    else {
      print DATAOUT "$columns[1] ";
    }      
  }
}
close (DATAOUT);
close $in;

What needs changing is the "my @columns = split..." line. At the moment it splits up the $line scalar whenever it has '9 spaces'. As the number of digits of the element numbers can vary, this is a poor way of extracting the data. Is it possible to just read from left to right, omitting all spaces and recording numbers only until the numbers are followed by more spaces (that way the percentage value is ignored)?

1
  • this seems to work: my @columns = split(/\s+/,$line); Commented Feb 2, 2012 at 16:18

5 Answers 5

1
#!/usr/bin/perl
use strict;
use warnings;

while (<>) {                        # read the file line by line
    if (/% *$/) {                   # if the line ends in a percent sign
        my @columns = split;        # create columns
        print $columns[0], "\n";    # print the first one
    }
    last if /={10}/;                # end of processing
}
Sign up to request clarification or add additional context in comments.

Comments

1

A one-liner using flip-flop:

perl -ne '
  if ( m/\A\s*(?i)element\s+no/ .. ($end = /\A\s*=+\s*\Z/) ) {
    printf qq[$1\n] if m/\A\s*(\d+)/;
    exit 0 if $end
  }
' infile

Result:

20004
20013
11189
20207
11157
11183
10665
20182
11160

Comments

0
#!/usr/bin/perl
use strict;
use warnings;

while (my $f= shift) {
   open(F, $f) or (warn("While opening $f: $!", next);
   my foundstart=0;
  while(<F>) {
     ($foundstart++, next) if /^\s#Element/;
     last if /\s*=+/;
     print $_ if $foundstart;
  }
  $foundstart=0;
  close(F);
}

1 Comment

It has compile errors. 1.- There is a miss of a parentheses in the warn instruction. 2.- Declare foundstart variable as a scalar with $ and in the next regex I think there is a typo with # instead *. It then prints numbers but percentages too in my test.
0
#!/usr/bin/perl
use strict;
use warnings;

open my $rh, '<', 'input.txt' or die "Unable to open file: $!\n";
open my $wh, '>', 'output.txt' or die "Unable to open file: $!\n";

while (my $line = <$rh>) {        
    last if $line =~ /^ ={50}/;
    next unless $line =~ /^ {6}(\d+)/;
    print $wh "$1\n";
}

close $wh;

Comments

0

You could do it by running this one-liner in a command shell.

On *nix:

cat in_file.txt | perl -ne 'print "$1\n" if ( m/\s*(\d+)\s*\d+\.\d+/ )' > out_file.txt

On Windows:

type in_file.txt | perl -ne "print qq{$1\n} if ( m/\s*(\d+)\s*\d+\.\d+/ )" > out_file.txt

2 Comments

He wants to stop reading from file when the line with the equals signs are reached though.
The cat is a waste of a process. The -n switch causes an iteration over the file names in @ARGV as if you had written LINE: while (<>) { ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.