read input file, match and remove data and write remaining lines to a new file - perl

I am stuck trying to get this to write out the contents of the file. What I am trying to do is open an input file, filter out/remove the matched line and write to a new file. Can someone show me how to do this properly? Thanks.
use strict;
use warnings;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new ({ binary => 1 }) or
die "Cannot use CSV: ".Text::CSV_XS->error_diag ();
open my $fh, "<:encoding(UTF-16LE)", "InputFile.txt" or die "cannot open file: $!";
my #rows;
while (my $row = $csv->getline ($fh)) {
my #lines;
shift #lines if $row->[0] =~ m/Global/;
my $newfile = "NewFile.txt";
open(my $newfh, '>', $newfile) or die "Can't open";
print $newfh #lines;
}
$csv->eof or $csv->error_diag ();
close $fh;

Open the output file outside of the loop. As you read each line, decide if you want to keep it. If yes, write to output file. If not, don't do anything.
Something like the following (untested):
use strict;
use warnings;
use Text::CSV_XS;
my ($input_file, $output_file) = qw(InputFile.txt NewFile.txt);
my $csv = Text::CSV_XS->new ({ binary => 1 })
or die sprintf("Cannot use CSV: %s\n", Text::CSV_XS->error_diag);
open my $infh, "<:encoding(UTF-16LE)", $input_file
or die "Cannot open '$input_file': $!";
open my $outfh, '>', $output_file
or die "Cannot open '$output_file': $!";
while (my $row = $csv->getline($infh)) {
next if $row->[0] =~ m/Global/;
unless ( $csv->print($outfh, $row) ) {
die sprintf("Error writing to '%s': %s",
$output_file,
$csv->error_diag
);
}
}
close $outfh
or die "Cannot close '$output_file': $!";
close $infh
or die "Cannot close '$input_file': $!";
$csv->eof
or die "Processing of '$input_file' terminated prematurely";

Related

how to change the contents in the file in perl?

I am trying to open one file read oneline in it at a time then open the another file and try to search for some part of the line read from the first file in the second file and try to replace all instances with the other part of the line read from the first file.When i am executing it its getting executed and i am able to see the result on the console but the files are not getting modified. What could be the mistake. Can some one please suggest this.
use strict;
use warnings;
use autodie; # die if problem reading or writing a file
my $filename = 'compare.txt';
open(my $fh, '+<', $filename) or die "Could not open file '$filename' $!";
while(<$fh>){
my $readline= "$_";
print("\n");
my #arr=split(',',$readline);
print($arr[0]."\n".$arr[1]);
replace($arr[0],$arr[1]);
}
close $fh;
sub replace
{
my $search=shift(#_);
my $replace=shift(#_);
my $filename2 = 'replace.txt';
open(my $fh1, '+<', $filename2) or die "Could not open file '$filename' $!";
while(<$fh1>)
{
my $readline2= "$_";
$readline2=~s/$search/$replace/g;
print($readline2);
print("\n");
}
close $fh1;
}
As a huge fan of the Path::Tiny module, I would do the above as:
use 5.014;
use warnings;
use Path::Tiny;
my %rep = map { split /,/ } path('compare.txt')->lines({chomp => 1});
path("replace.txt")->edit_lines( sub {
while(my($key,$val) = each(%rep)) {
s/$key/$val/g;
}
});
In your sub, when you are iterating the lines in your file, you should write it back to a file. The regex substitute doesn't automatically write it back to file.
use strict;
use warnings;
use autodie; # die if problem reading or writing a file
use File::Copy;
my $filename = 'compare.txt';
open(my $fh, '+<', $filename) or die "Could not open file '$filename' $!";
while(<$fh>){
my $readline= "$_";
print("\n");
my #arr=split(',',$readline);
print($arr[0]."\n".$arr[1]);
replace($arr[0],$arr[1]);
}
close $fh;
sub replace
{
my $search=shift(#_);
my $replace=shift(#_);
my $filename2 = 'replace.txt';
open(my $fh1, '+<', $filename2) or die "Could not open file '$filename' $!";
#open file to write to
open $newfile, '>', 'replace_tmp.txt';
while(<$fh1>)
{
chomp;
my $readline2= "$_";
$readline2=~s/$search/$replace/g;
print( $newfile, $readline2);
print($newfile, "\n");
}
close($fh1);
close($newfile);
move ('replaced.txt', 'replace.txt');
}
This is simple way of doing it. You can use File::Tie to write back to the same file and avoid renaming it, or refer to perldoc

Perl: Couldn't open a file with file name as input

I am trying to copy lines of a file to another file.I want to give filenames for both input and output file. I tried to do without asking for any input parameters and it worked fine but with filename as input it failed.Here is my code:
use strict;
use warnings;
#names of file to be input and output
my $inputfile = <STDIN>;
my $outputfile = <STDIN>;
open(INPUT,'<', $inputfile)
or die "Could not open file '$inputfile' $!";
open(OUTPUT, '>', $outputfile)
or die "Could not open file '$outputfile' $!";
while (<INPUT>) {
print OUTPUT;
}
close INPUT;
close OUTPUT;
print "done\n";
chomp your input variables to remove the newlines:
use strict;
use warnings;
#names of file to be input and output
my $inputfile = <STDIN>;
my $outputfile = <STDIN>;
chomp $inputfile;
chomp $outputfile;
open(INPUT,'<', $inputfile)
or die "Could not open file '$inputfile' $!";
open(OUTPUT, '>', $outputfile)
or die "Could not open file '$outputfile' $!";
while (<INPUT>) {
print OUTPUT;
}
close INPUT;
close OUTPUT;
print "done\n";

Remove the first line from my directory

how can i remove the first line from my list of file , this is my code,
open my directory:
use strict;
use warnings;
use utf8;
use Encode;
use Encode::Guess;
use Devel::Peek;
my $new_directory = '/home/lenovo/corpus';
my $directory = '/home/lenovo/corpus';
open( my $FhResultat, '>:encoding(UTF-8)', $FichierResulat );
my $dir = '/home/corpus';
opendir (DIR, $directory) or die $!;
my #tab;
while (my $file = readdir(DIR)) {
next if ($file eq "." or $file eq ".." );
#print "$file\n";
my $filename_read = decode('utf8', $file);
#print $FichierResulat "$file\n";
push #tab, "$filename_read";
}
closedir(DIR);
open my file:
foreach my $val(#tab){
utf8::encode($val);
my $filename = $val;
open(my $in, '<:utf8', $filename) or die "Unable to open '$filename' for read: $!";
rename file
my $newfile = "$filename.new";
open(my $out, '>:utf8', $newfile) or die "Unable to open '$newfile' for write: $!";
remove the first line
my #ins = <$in>; # read the contents into an array
chomp #ins;
shift #ins; # remove the first element from the array
print $out #ins;
close($in);
close $out;
the probem my new file is empty !
rename $newfile,$filename or die "unable to rename '$newfile' to '$filename': $!";
}
It seems true but the result is an empty file.
The accepted pattern for doing this kind of thing is as follows:
use strict;
use warnings;
my $old_file = '/path/to/old/file.txt';
my $new_file = '/path/to/new/file.txt';
open(my $old, '<', $old_file) or die $!;
open(my $new, '>', $new_file) or die $!;
while (<$old>) {
next if $. == 1;
print $new $_;
}
close($old) or die $!;
close($new) or die $!;
rename($old_file, "$old_file.bak") or die $!;
rename($new_file, $old_file) or die $!;
In your case, we're using $. (the input line number variable) to skip over the first line.

Perl iterating through each line in a file and and appending to the end of each line in another file - follow up

I have a follow up question regarding an ealier post.
The post in question is:
Perl iterating through each line in a file and appending to the end of each line in another file
I used:
use warnings;
use strict;
open my $animals, '<', 'File1.txt' or die "Can't open animals: $!";
open my $payloads, '<', 'File2.txt' or die "Can't open payloads: $!";
my #payloads = <$payloads>; #each line of the file into an array
close $payloads or die "Can't close payloads: $!";
while (my $line = <$animals>) {
chomp $line;
print $line.$_ foreach (#payloads);
}
close $animals or die "Can't close animals: $!";
This works fine for files that look like this:
file 1: file 2:
line1 lineA
line2 lineB
line3 lineC
but not for files that look like this:
<01 line1
<02 line2
So what I want to do is the following:
file 1: file 2:
<01 line1 <AA lineAA
<02 line2 <AB lineAB
should become:
file 3:
<01_AA line1lineAA
<01_AB line1lineAB
<02_AA line2lineAA
<02_AB line2lineAB
I have tried to solve it by splitting the strings on the tab using while loops in while loops (see below), but I cannot get it to work.
my script:
#!C:/perl64/bin/perl.exe
use warnings;
use strict;
open my $file1, '<', 'file1.fasta' or die "Can't open file1: $!";
open my $file2, '<', 'file2.fasta' or die "Can't open file2: $!";
open(OUT, '>', 'file3.fasta') or die "Cannot write $!";
while (<$file2>)
{
chomp;
my ($F2_Id, #SF2_seq) = split (/\t/, $_);
while (<$file1>)
{
chomp;
my ($F1_Id, #F1_seq) = split (/\t/, $_);
foreach my $seq (#F1_seq)
{
print OUT $F1_Id,"_",$F2_Id,"\t",$seq.$_ foreach (#F2_seq),"\n";
}
close;
}
}
I started with perl just recently so I can imagine that there are a lot of faults in the script.
I'm sorry for the really long post, but I would appriciate any help.
You can store the id and seq of the first file in an array of arrays.
You also have to replace the < in the second file with _.
#!/usr/bin/perl
use warnings;
use strict;
open my $LEFT, '<', 'file1.fasta' or die "Can't open file1: $!";
open my $RIGHT, '<', 'file2.fasta' or die "Can't open file2: $!";
open my $OUT, '>', 'file3.fasta' or die "Cannot write: $!";
my #left;
while (<$LEFT>) {
chomp;
push #left, [ split /\t/ ];
}
while (<$RIGHT>) {
chomp;
my ($id, $seq) = split /\t/;
$id =~ s/</_/;
print {$OUT} "$_->[0]$id\t$_->[1]$seq\n" for #left;
}
close $OUT or die "Cannot close: $!";

Combining two csv files together in perl

Hi i'm very new to perl and i've got litle knowledge on it but i'm trying to create a script that conbines two .csv files into a new one
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV_XS;
my #rows;
{ # Read the CSV file
my $csv = Text::CSV_XS->new() or die "Cannot use Text::CSV_XS ($!)";
my $file = "file.csv";
open my $fh, '<', $file or die "Cannot open $file ($!)";
while (my $row = $csv->getline($fh)) {
push #rows, $row;
}
$csv->eof or $csv->error_diag();
close $fh or die "Failed to close $file ($!)";
}
{ # Gather the data
foreach my $row (#rows) {
foreach my $col (#{$row}) {
$col = uc($col);
}
print "\n";
}
}
# (over)Write the data
# Needs to be changed to ADD data
{
my $csv = Text::CSV_XS->new({ binary => 1, escape_char => undef })
or die "Cannot use Text::CSV ($!)";
my $file = "output.csv";
open my $fh, '>', $file or die "Cannot open $file ($!)";
$csv->eol("\n");
foreach my $row (#rows) {
$csv->print($fh, \#{$row}) or die "Failed to write $file ($!)";
}
close $fh or die "Failed to close $file ($!)";
}
this is my current code i do know this over write's the data insted of actually adding it to the new file but this is how far i managed to get with the limited time and knowledge i've got on perl
the csv format of both files are the same.
"Header1";"Header2";"Header3";"Header4";"Header5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
I believe the issue is here:
open my $fh, '>', $file
or die "Cannot open $file ($!)";
If I remember my Perl properly, the line should read:
open my $fh, '>>', $file
or die "Cannot open $file ($!)";
The >> should open the file handle $fh for append instead of for overwrite.
you could try something like this
opendir(hand,"DIRPATH");
#files = readdir(hand);
closedir(hand);
foreach(#files){
if(/\.csv$/i) { #if the filename has .csv at the end
push(#csvfiles,$_);
}
}
foreach(#csvfiles) {
$csvfile=$_;
open(hanr,"DIRPATH".$csvfile)or die"error $!\n"; #read handler
open(hanw , ">>DIRPATH"."outputfile.csv") or die"error $! \n"; #write handler for creating new sorted files
#lines=();
#lines=<hanr>;
foreach $line (#lines){
chomp $line;
$count++;
next unless $count; # skip header i.e the first line containing stock details
print hanw join $line,"\n";
}
$count= -1;
close(hanw);
close(hanr);
}`