1

I want to process a file in such a way that, read from multiple lines and make a new file which will have a single line corresponding to this.

For eg.: Input File:

12345   1   -   -   -

12346   -   2   -   4

12347   -   -   3   -

12348   5   -   -   -

12349   -   6   -   8

12350   -   -   7   -

Output file :

12346   1   2   3   4

12349   5   6   7   8

Take 3 lines to make a complete row.

How to do this in perl?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 4
    How does the output correspond to the input? What is the logic behind it? And what have you tried so far? Show the code. – Matt Healy Dec 02 '13 at 04:30
  • 1. Read the first 3 lines. 2. Keep the first 5 characters of the middle line. 3. Check if the 6th character of first line is NOT '-' then append it to the string from step2 otherwise check it with 2nd line 5th character and also check it with 3rd line 6th character. Repeat step3 3 more times. 4. Read the next 3 lines and do step2 and on until you reach end of file. – chuthan20 Dec 02 '13 at 04:31
  • what if first line 6 charter is -? – Thiyagu ATR Dec 02 '13 at 07:39

4 Answers4

3

Do it in 3 simple steps:

  1. Create a hash, keeping 1st word as key.

  2. Read from files and keep the input in an array.

  3. Print the elements to a new file against each each key.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
2
perl -lane'
  $r = $. % 3;
  $f = $F[0] if $r==2; 
  $arr[$_] += $F[$_] for 1 .. $#F;
  if (!$r) { print "$f @arr"; @arr=() }
' file

output

12346  1 2 3 4
12349  5 6 7 8
mpapec
  • 50,217
  • 8
  • 67
  • 127
1

i think this will help you,if any clarification let me know:

input file is:

12345|1|-|-|-
12346|-|2|-|4
12347|-|-|3|-
12348|5|-|-|-
12349|-|6|-|8
12350|-|-|7|-

script

use strict;
use warnings;
sub processor{
(my @tmp )=@_;
        my @inner;
        shift(@tmp);
            foreach my $element(@tmp){
                $_=$element;
                if((m/[0-9]/)){
                    push(@inner,$element);
                }
            }
return @inner;
}
open(INFILE,"infile.dat") or die "$!";
open(OFILE,">outfile.dat") or die "$!";
my @ecollector;
my $keyVal;
my $counter;
while(<INFILE>){
        chomp($_);
        my @tmp=split('\|',$_);
        if(($. % 3) ne 0){
            if(($. % 3) eq 2){ $keyVal=$tmp[0];}
            push(@ecollector,processor(@tmp));
        }
        else{
            push(@ecollector,processor(@tmp));
            print OFILE "$keyVal\t".join("\t",sort(@ecollector))."\n";
            @ecollector=();
        }   
}
close(INFILE);
close(OFILE);
Thiyagu ATR
  • 2,224
  • 7
  • 30
  • 44
0

This is my solution. input, and output files are 1st and 2nd argument from command-line:

#!/usr/bin/perl

use warnings;
use strict;

open(DATA, "<", $ARGV[0]) or die $!;
open(OUTPUT, ">", $ARGV[1]) or die $!;

my $count = 0;
my $id = 0;
my @arr;

foreach (<DATA>){
    chomp;
    my @data;
    # if line is not empty
    if($_ ne ""){
        @data = split(" ", $_);
        $id = $data[0];

        # merge data
        for(my $i = 1; $i <= $#data; $i++){
            if($data[$i] ne "-"){
                $arr[$i] = $data[$i];
            }
        }

        $count++;
        if ($count == 2){
            $arr[0] = $id;
        } elsif ($count == 3){
            # reset countable variable
            $count = 0;
            # print output
            print OUTPUT join " ",@arr,"\n";
        }
    }
}
close(DATA);
close(OUTPUT);
Dai Nguyen-Van
  • 229
  • 2
  • 4