parsing file through an array

A

Andrea Spitaleri

Hi
I have a file and I would like to remove from it the lines that match
the values from an array.
Here is the code that I unsuccessfully tried:
#!/usr/bin/perl

use warnings;
use strict;

open (FILE,"<$ARGV[0]") or die "$!";


my @h = ("H","N");

while (my $line=<FILE>){
chomp $line;
foreach my $i (@h){
next if ($line=~ / +$i/);
print "$line\n";
}
}
and the file is something like that:
2 C2 -0.4158 0.5051 -0.2805 C.3 1 UNK
0.2800
3 H3 -0.0655 0.8795 0.6861 H 1 UNK
0.0000
13 H13 -2.5997 0.4032 -0.4902 H 1 UNK
0.0000
14 N14 -2.0421 -0.8226 1.0724 N.2 1 UNK
0.0476
15 C15 -1.9418 -2.1366 1.4487 C.2 1 UNK
0.0365
1 O1 -0.4981 1.6455 -1.1635 O.3 1 UNK
-0.6800
2 C2 -0.4158 0.5051 -0.2805 C.3 1 UNK
0.2800
................
Swapping next with print "found $i" after the foreach I figured out
that the loop is working properly (it matches that array values) but
doesn't next.
What is it wrong????

thanks

regards

and
 
A

Anno Siegel

Andrea Spitaleri said:
Hi
I have a file and I would like to remove from it the lines that match
the values from an array.
Here is the code that I unsuccessfully tried:
#!/usr/bin/perl

use warnings;
use strict;

open (FILE,"<$ARGV[0]") or die "$!";


my @h = ("H","N");

while (my $line=<FILE>){
chomp $line;
foreach my $i (@h){
next if ($line=~ / +$i/);
print "$line\n";
}
}
and the file is something like that:
2 C2 -0.4158 0.5051 -0.2805 C.3 1 UNK
0.2800
3 H3 -0.0655 0.8795 0.6861 H 1 UNK
0.0000
13 H13 -2.5997 0.4032 -0.4902 H 1 UNK
0.0000
14 N14 -2.0421 -0.8226 1.0724 N.2 1 UNK
0.0476
15 C15 -1.9418 -2.1366 1.4487 C.2 1 UNK
0.0365
1 O1 -0.4981 1.6455 -1.1635 O.3 1 UNK
-0.6800
2 C2 -0.4158 0.5051 -0.2805 C.3 1 UNK
0.2800
...............
Swapping next with print "found $i" after the foreach I figured out
that the loop is working properly (it matches that array values) but
doesn't next.

If you look at your output closely, you'll find that it prints
every line twice, except those that match, which are printed only
once. The reason is your inner loop. It shouldn't print lines
before it is done, but only determine if there is a match.

BTW, there is no reason to chomp the lines if you immediately add
the "\n" back on.

while (my $line=<FILE>){
my $match;
foreach my $i (@h){
$match ||= $line=~ / +$i/;
last if $match;
}
print $line unless $match;
}

A better way is to construct a single regex that matches all unwanted
lines.

/ [HN]/ or print while <FILE>;

Anno
 
B

Ben Morrow

Quoth (e-mail address removed) (Andrea Spitaleri):
Hi
I have a file and I would like to remove from it the lines that match
the values from an array.
Here is the code that I unsuccessfully tried:
#!/usr/bin/perl

use warnings;
use strict;

open (FILE,"<$ARGV[0]") or die "$!";

Better is:

open my $FILE, '<', $ARGV[0] or die "can't open $ARGV[0]: $!";

Better still is simply to use the magic filehandle ARGV.
my @h = ("H","N");

I would have written

my @h = qw/H N/;

, but you may not like that.
while (my $line=<FILE>){

Use $_: that's what it's there for.

while (<FILE>) {

or, if you're using ARGV,

while ( said:
chomp $line;

Why? You're just going to stick it back on the end again when you print.
foreach my $i (@h){
next if ($line=~ / +$i/);

This will next the for loop, not the while loop. You need to give the
while a label:

LINE: while (<>) {
for my $i (@h) {
next if / +\Q$i/;

Note the \Q: you should always use this if you mean to match a
variable's contents literally.
print "$line\n";

This should go after the for loop.

As Anno said, it would be better to construct a regex which matches all
the alternatives:

my @h = qw/H A/;
my $re = join '|', map { qr/ +\Q$_/ } @h;

while (<>) {
next if /$re/;
print;
}

Ben
 
D

David K. Wall

Jim Gibson said:
Andrea Spitaleri said:
Hi
I have a file and I would like to remove from it the lines that
match the values from an array.
Here is the code that I unsuccessfully tried:
#!/usr/bin/perl

use warnings;
use strict;

open (FILE,"<$ARGV[0]") or die "$!";


my @h = ("H","N");

while (my $line=<FILE>){
chomp $line;
foreach my $i (@h){
next if ($line=~ / +$i/);
print "$line\n";
}
}

And to add to what Anno and Ben have already suggested (putting me
in august company, indeed), you may also use grep with the array
of strings to match:

my @h = qw/H N/;
while (my $line = <FILE>){
print $line unless grep($line =~ / +\Q$_/,@h);
}

I am not claiming this is better or faster, just different. :)

Or use Tie::File, as the FAQ suggests:

use strict;
use warnings;
use Tie::File;

my @lines;
tie @lines, 'Tie::File', 'filename' or die "Error tieing file: $!";
@lines = grep { !/ H| N/ } @lines;
untie @lines;
 
X

xspirix

Thanks again for the clear and exhaustive explanations. :D
I am learning a lot with you... :))
thanks again

and
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,413
Latest member
KeiraLight

Latest Threads

Top