Skipping a String in an Array, Perl

I am relatively new to Perl, and I came across this project that I find difficult to work with. The object of the project is to compare two csv files, one of which will contain: $ name, $ model, $ version and the other, which will contain: $ Name2, $ drive, $ storage ultimately the RESULT file will contain the corresponding lines and collect the following information : $ name, $ model, $ version, $ disk, $ storage.

I managed to do this, but my problem is that when one of the elements of the missed programs is interrupted. When it encounters a line in the file, the missing element, it stops at that line. How can I fix this problem? Any suggestions or a way, how can I possibly skip this line and continue?

Here is my code:

open( TESTING, '>testing.csv' ); # Names will be printed to this during testing. only .net ending names should appear open( MISSING, '>Missing.csv' ); # Lines with missing name feilds will appear here. #open (FILE,'C:\Users\hp-laptop\Desktop\file.txt'); #my (@array) =<FILE>; my @hostname; #stores names #close FILE; #***** TESTING TO SEE IF ANY OF THE LISTED ITEMS BEGIN WITH A COMMA AND DO NOT HAVE A NAME. #***** THESE OBJECTS ARE PLACED INTO THE MISSING ARRAY AND THEN PRINTED OUT IN A SEPERATE #***** FILE. #open (FILE,'C:\Users\hp-laptop\Desktop\file.txt'); #test if ( open( FILE, "file.txt" ) ) { } else { die " Cannot open file 1!\n:$!"; } $count = 0; $x = 0; while (<FILE>) { ( $name, $model, $version ) = split(","); #parsing #print $name; chomp( $name, $model, $version ); if ( ( $name =~ /^\s*$/ ) && ( $model =~ /^\s*$/ ) && ( $version =~ /^\s*$/ ) ) #if all of the fields are blank ( just a blank space) { #do nothing at all } elsif ( $name =~ /^\s*$/ ) { #if name is a blank $name =~ s/^\s*/missing/g; print MISSING "$name,$model,$version\n"; #$hostname[$count]=$name; #$count++; } elsif ( $model =~ /^\s*$/ ) { #if model is blank $model =~ s/^\s*/missing/g; print MISSING"$name,$model,$version\n"; } elsif ( $version =~ /^\s*$/ ) { #if version is blank $version =~ s/^\s*/missing/g; print MISSING "$name,$model,$version\n"; } # Searches for .net to appear in field "$name" if match, it places it into hostname array. if ( $name =~ /.net/ ) { $hostname[$count] = $name; $count++; } #searches for a comma in the name feild, puts that into an array and prints the line into the missing file. #probably won't have to use this, as I've found a better method to test all of the feilds ( $name,$model,$version) #and put those into the missing file. Hopefully it works. #foreach $line (@array) #{ #if($line =~ /^\,+/) #{ #$line =~s/^\,*/missing,/g; #$missing[$x]=$line; #$x++; #} #} } close FILE; for my $hostname (@hostname) { print TESTING $hostname . "\n"; } #for my $missing(@missing) #{ # print MISSING $missing; #} if ( open( FILE2, "file2.txt" ) ) { #Run this if the open succeeds #open outfile and print starting header open( RESULT, '>resultfile.csv' ); print RESULT ("name,Model,version,Disk, storage\n"); } else { die " Cannot open file 2!\n:$!"; } $count = 0; while ( $hostname[$count] ne "" ) { while (<FILE>) { ( $name, $model, $version ) = split(","); #parsing #print $name,"\n"; if ( $name eq $hostname[$count] ) # I think this is the problem area. { print $name, "\n", $hostname[$count], "\n"; #print RESULT"$name,$model,$version,"; #open (FILE2,'C:\Users\hp-laptop\Desktop\file2.txt'); #test if ( open( FILE2, "file2.txt" ) ) { } else { die " Cannot open file 2!\n:$!"; } while (<FILE2>) { chomp; ( $name2, $Dcount, $vname ) = split(","); #parsing if ( $name eq $name2 ) { chomp($version); print RESULT"$name,$model,$version,$Dcount,$vname\n"; } } } $count++; } #open (FILE,'C:\Users\hp-laptop\Desktop\file.txt'); #test if ( open( FILE, "file.txt" ) ) { } else { die " Cannot open file 1!\n:$!"; } } close FILE; close RESULT; close FILE2; 
+6
source share
2 answers

I think you want next , which allows you to immediately complete the current iteration and start the following:

 while (<FILE>) { ( $name, $model, $version ) = split(","); next unless( $name && $model && $version ); ...; } 

The condition you use depends on what values ​​you accept. In my examples, I assume that all values ​​should be true. If they just need to not be an empty string, maybe you can check its length:

 while (<FILE>) { ( $name, $model, $version ) = split(","); next unless( length($name) && length($model) && length($version) ); ...; } 

If you know how to check each field, you may have routines for them:

 while (<FILE>) { ( $name, $model, $version ) = split(","); next unless( length($name) && is_valid_model($model) && length($version) ); ...; } sub is_valid_model { ... } 

Now you just need to decide how to integrate this into what you are already doing.

+2
source

You should start by adding use strict and use warnings at the beginning of your program and declaring all variables with my at the beginning of their use. This will show many simple errors that are otherwise difficult to detect.

You should also use a three-parameter for open and lexical file descriptors, and the Perl idiom for checking exceptions when opening files is to add or die to the open call. if with an empty block for the waste space the paths to success become unreadable. The open call should look like this:

 open my $fh, '>', 'myfile' or die "Unable to open file: $!"; 

Finally, it is much safer to use the Perl module when you are processing CSV files, as there are many errors when using simple split /,/ . The Text::CSV module has done all the work for you and is available in CPAN.

The problem is that after reading to the end of the first file, you do not rewind or reopen it before re-reading from the same descriptor in the second nested loop. This means that the data from this file will no longer be read, and the program will behave as if it is empty.

A bad strategy is to read the same file hundreds of times to compose the corresponding records. If the file is of reasonable size, you must create a data structure in memory to store information. The Perl hash is ideal because it allows you to instantly search for data matching a given name.

I wrote a version of your code that demonstrates these points. It would be awkward for me to check the code, since I do not have sample data, but if you still have problems, let us know.

 use strict; use warnings; use Text::CSV; my $csv = Text::CSV->new; my %data; # Read the name, model and version from the first file. Write any records # that don't have the full three fields to the "MISSING" file # open my $f1, '<', 'file.txt' or die qq(Cannot open file 1: $!); open my $missing, '>', 'Missing.csv' or die qq(Unable to open "MISSING" file for output: $!); # Lines with missing name fields will appear here. while ( my $line = csv->getline($f1) ) { my $name = $line->[0]; if (grep $_, @$line < 3) { $csv->print($missing, $line); } else { $data{$name} = $line if $name =~ /\.net$/i; } } close $missing; # Put a list of .net names found into the testing file # open my $testing, '>', 'testing.csv' or die qq(Unable to open "TESTING" file for output: $!); # Names will be printed to this during testing. Only ".net" ending names should appear print $testing "$_\n" for sort keys %data; close $testing; # Read the name, disk and storage from the second file and check that the line # contains all three fields. Remove the name field from the start and append # to the data record with the matching name if it exists. # open my $f2, '<', 'file2.txt' or die qq(Cannot open file 2: $!); while ( my $line = $csv->getline($f2) ) { next unless grep $_, @$line >= 3; my $name = shift @$line; next unless $name =~ /\.net$/i; my $record = $data{$name}; push @$record, @$line if $record; } # Print the completed hash. Send each record to the result output if it # has the required five fields # open my $result, '>', 'resultfile.csv' or die qq(Cannot open results file: $!); $csv->print($result, qw( name Model version Disk storage )); for my $name (sort keys %data) { my $line = $data{$name}; if (grep $_, @$line >= 5) { $csv->print($result, $data{$name}); } } 
+2
source

Source: https://habr.com/ru/post/918294/


All Articles