I have some trouble
with array, how to read an array line in sequence from Input.
Here's my code.
sites.txt: (input file)
site1
site2
site3
program
#!/usr/bin/perl
my $file = 'sites.txt';
open(my $fh, '<:encoding(UTF-8)', $file)
or die "Couldn't open file !'$file' $!";
my #rows = <$fh>;
chomp #rows;
foreach my $site (#rows) {
$sitename = $site;
#domains = qw(.com .net .org);
foreach $dns (#domains){
$domain = $dns;
print "$site$dns\n";
}
}
and the output is like this
site1.com
site1.net
site1.org
site2.com
site2.net
site2.org
site3.com
site3.net
site3.org
I understand until that point,but i want make it the first element of array from #domains
reading until the end of Input line first,
then looping back to the 1st line of Input and going to the next element of array so
the output would be like this,
site1.com
site2.com
site3.com
site1.net
site2.net
site3.net
site1.org
site2.org
site3.org
it possible doing it? or need another module.sorry for basic question
I'll be really appreciated for the Answers.
thanks :)
You are iterating over all your sites and then (for each site) add the domain to the current site.
In pseudocode this is:
foreach site
foreach domain
print site + domain
Swap your loops so that the logic is
foreach domain
foreach site
print site + domain
Note that this is pseudocode, not Perl.
In "real" Perl this would look like:
#!/usr/bin/env perl
use strict;
use warnings;
my $file = 'sites.txt';
open( my $fh, '<:encoding(UTF-8)', $file )
or die "Couldn't open file !'$file' $!";
my #rows = <$fh>;
chomp #rows;
my #domains = qw(.com .net .org);
foreach my $dns (#domains) {
foreach my $site (#rows) {
print "$site$dns\n";
}
}
Output
site1.com
site2.com
site3.com
site1.net
site2.net
site3.net
site1.org
site2.org
site3.org
Please always include use strict; and use warnings; on top of your scripts. These two statements will show you the most common errors in your code.
Related
I have one file with ~90k lines of text in 4 columns.
col1 col2 col3 value1
...
col1 col2 col3 value90000
A second file contains ~200 lines, each one corresponding to a value from column 4 of the larger file.
value1
value2
...
value200
I want to read in each value from the smaller file, find the corresponding line in the larger file, and return that line. I have written a perl script that places all the values from the small file into an array, then iterates through that array using each value as a regex to search through the larger file. After some debugging, I feel like I have it almost working, but my script only returns the line corresponding to the LAST element of the array.
Here is the code I have:
open my $fh1, '<', $file1 or die "Could not open $file1: $!";
my #array = <$fh1>;
close $fh1;
my $count = 0;
while ($count < scalar #array) {
my $value = $array[$count];
open my $fh2, '<', $file2 or die "Could not open $file2: $!";
while (<$fh2>) {
if ($_ =~ /$value/) {
my $line = $_;
print $line;
}
}
close $fh2;
$count++;
}
This returns only:
col1 col2 col3 value200
I can get it to print each value of the array, so I know it's iterating through properly, but it's not using each value to search the larger file as I intended. I can also plug any of the values from the array into the $value variable and return the appropriate line, so I know the lines are there. I suspect my bug may have to do with either:
newlines in the array elements, since all the elements have a newline except the last one. I've tried chomp but get the same result.
or
something to do with the way I'm handling the second file with opening/closing. I've tried moving or removing the close command and that either breaks the code or doesn't help.
You should only be reading the 90k line file once, and checking each value from the other file against the fourth column of each line as you do, instead of reading the whole large file once per line of the smaller one:
#!usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
my ($file1, $file2) = #ARGV;
# Read the file of strings to match against
open my $fh1, '<', $file1 or die "Could not open $file1: $!";
my %words = map { chomp; $_ => 1 } <$fh1>;
close $fh1;
# Process the data file in one pass
open my $fh2, '<', $file2 or die "Could not open $file2: $!";
while (my $line = <$fh2>) {
chomp $line;
# Only look at the fourth column
my #fields = split /\s+/, $line, 4;
say $line if exists $words{$fields[3]};
}
close $fh2;
Note this uses a straight up string comparison (Via hash key lookup) against the last column instead of regular expression matching - your sample data looks like that's all that's needed. If you're using actual regular expressions, let me know and I'll update the answer.
Your code does look like it should work, just horribly inefficiently. In fact, after adjusting your sample data so that more than one line matches, it does print out multiple lines for me.
Slightly different approach to the problem
use warnings;
use strict;
use feature 'say';
my $values = shift;
open my $fh1, '<', $values or die "Could not open $values";
my #lookup = <$fh1>;
close $fh1;
chomp #lookup;
my $re = join '|', map { '\b'.$_.'\b' } #lookup;
((split)[3]) =~ /$re/ && print while <>;
Run as script.pl value_file data_file
I have a CSV file with the following information seperated by commas ...
Owner,Running,Passing,Failing,Model
D42,21,54,543,Yes
T43,54,76,75,No
Y65,76,43,765,Yes
I want to open this CSV file and place its containments inside of a perl hash in my program. I am also interested in the code needed to print a specific element inside of the has. For example, how I will print the "Passing" count for the "Owner" Y65.
The code I currently have:
$file = "path/to/file";
open $f, '<', $files, or die "cant open $file"
while (my $line = <$f>) {
#inside here I am trying to take the containments of this file and place it into a hash. I have tried numerous ways of trying this but none have seemed to work. I am leaving this blank because I do not want to bog down the visibility of my code for those who are kind enough to help and take a look. Thanks.
}
AS well as placing the csv file inside of a hash I also need to understand the syntax to print and navigate through specific elements. Thank you very much in advance.
Here is an example of how to put the data into a hash %owners and later (after having read the file) extract a "passing count" for a particular owner. I am using the Text::CSV module to parse the lines of the file.
use feature qw(say);
use open qw(:std :utf8); # Assume UTF-8 files and terminal output
use strict;
use warnings qw(FATAL utf8);
use Text::CSV;
my $csv = Text::CSV->new ( )
or die "Cannot use CSV: " . Text::CSV->error_diag ();
my $fn = 'test.csv';
open my $fh, "<", $fn
or die "Could not open file '$fn': $!";
my %owners;
my $header = $csv->getline( $fh ); # TODO: add error checking
while ( my $row = $csv->getline( $fh ) ) {
next if #$row == 0; # TODO: more error checking
my ($owner, #values) = #$row;
$owners{$owner} = \#values;
}
close $fh;
my $key = 'Y65';
my $index = 1;
say "Passing count for $key = ", $owners{$key}->[$index];
Since it's not really clear what "load a CSV file into a perl hash" means (Nor does it really make sense. An array of hashes, one per row, maybe, if you don't care about keeping the ordering of fields, but just a hash? What are the keys supposed to be?), let's focus on the rest of your question, in particular
how I will print the "Passing" count for the "Owner" Y65.
There are a few other CSV modules that might be of interest that are much easier to use than Text::CSV:
Tie::CSV_File lets you access a CSV file like a 2D array. $foo[0][0] is the first field of the first row of the tied file.
So:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use Tie::CSV_File;
my $csv = "data.csv";
tie my #data, "Tie::CSV_File", $csv or die "Unable to tie $csv!";
for my $row (#data) {
say $row->[2] and last if $row->[0] eq "Y65";
}
DBD::CSV lets you treat a CSV file like a table in a database you can run SQL queries on.
So:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use DBI;
my $csv = "data.csv";
my $dbh = DBI->connect("dbi:CSV:", undef, undef,
{ csv_tables => { data => { f_file => $csv } } })
or die $DBI::errstr;
my $owner = "Y65";
my $p = $dbh->selectrow_arrayref("SELECT Passing FROM data WHERE Owner = ?",
{}, $owner);
say $p->[0] if defined $p;
Text::AutoCSV has a bunch of handy functions for working with CSV files.
So:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use Text::AutoCSV;
my $csv = "data.csv";
my $acsv = Text::AutoCSV->new(in_file => $csv) or die "Unable to open $csv!";
my $row = $acsv->search_1hr("OWNER", "Y65");
say $row->{"PASSING"} if defined $row;
This last one is probably closest to what I think you think you want.
I'm trying to check the existence of words from a file in a hash, and if so to display the corresponding hash key and value.
So far, I've been able to do it with an array #motcherches which values are given in the script.
I can't find a way to give as values to this array words from a external file (here FILEDEUX).
Could you point me in the right direction?
(Please don't hesitate to correct my way of explaining my problem.)
#!/usr/bin/perl
use v5.10;
use strict;
use warnings;
my $hashtable = $ARGV[0];
my $textecompare = $ARGV[1];
open FILE,"<$hashtable" or die "Could not open $hashtable: $!\n";
open FILEDEUX,"<$textecompare" or die "Could not open $textecompare: $!\n";
while ( my $line = <FILE>)
{
chomp($line);
my %elements = split(" ",$line);
my #motcherches = qw/blop blup blip blap/;
foreach my $motcherches (#motcherches) {
while ((my $key, my $value) = each (%elements)) {
# Check if element is in hash :
say "$key , $value" if (exists $elements{$motcherches}) ;
}
}
}
close FILE;
close FILEDEUX;
EDIT: Example inputs
FILE (transformed into %elements hash)
Zieler player
Chilwell player
Ulloa player
Mahrez player
Ranieri coach
============================================================================
FILEDEUX (transformed into motcherchesarray)
One save is quickly followed by another, and this time Zieler had to be a little sharper to keep it out.
Izaguirre gives Mahrez a taste of his own medicine by beating him all ends up down the left flank, although the Leicester winger gave up far too easily.
Claudio Ranieri will be happy with what he has seen from his side so far.
=============================================================================
Expected output:
Zieler player
Mahrez player
Ranieri coach
use strict;
use warnings;
use feature qw/ say /;
# Read in your paragraph of text here:
open my $text, '<', 'in.txt' or die $!;
my %data;
while(<$text>){
chomp;
$data{$_}++ for split; # by default split splits on ' '
}
my %players;
while(<DATA>){
chomp;
my #field = split;
say if $data{$field[0]};
}
__DATA__
Zieler player
Chilwell player
Ulloa player
Mahrez player
Ranieri coach
Everything is fine but add the chomp in your program
while ( my $line = <FILE>)
{
chomp($line);
my %elements = split(" ",$line);
I want to open a file, push 5 lines into an array for later use (or what is left if less than 5) and remove those 5 lines from the file as well.
It does not matter whether I am removing (or pushing) from head or tail of file.
I have used Tie::File in the past and am willing to use it, but I cannot figure it out with or without the Tie module.
use Tie::File;
my $limit='5';
$DataFile='data.txt';
###open my $f, '<', $DataFile or die;
my #lines;
tie (#lines, 'Tie::File', $DataFile);
$#lines = $limit;
###while( <#lines> ) {
shift #lines if #lines <= $limit;
push (#lines, $_);
###}
print #lines;
untie #lines;
Also tried File::ReadBackwards from an example I found but, I cannot figure out how to get the array of 5.
my $pos = do {
my $fh = File::ReadBackwards->new($DataFile) or die $!;
##lines =(<FILE>)[1..$limit];
#$fh->readline() for 1..$limit;
my $log_line = $fh->readline for 1..$limit;
print qq~ LogLine $log_line~;
$fh->tell()};
All that said, this came close, but no cigar. How do I get the 5 into an array?
use File::ReadBackwards;
my $num_lines = 5;
my $pos = do {
my $fh = File::ReadBackwards->new($DataFile) or die $!;
$fh->readline() for 1..$num_lines;
$fh->tell()};
truncate($DataFile, $pos)or die $!;
I will check each line in the array against a regex later on. They still need to be removed from the file either way.
If you extract the last five lines instead of the first five, then you can use truncate instead of writing the entire file. Furthermore, you can use File::ReadBackwards to get those five lines without reading the entire file. That makes the following solution insanely faster than Tie::File for large files (and it will use far less memory):
use File::ReadBackwards qw( );
my $num_lines = 5;
my $fh = File::ReadBackwards->new($DataFile)
or die("Can't open $DataFile: $!\n");
my #extracted_lines;
while ($_ = $fh->readline() && #extracted_lines < $num_lines) {
push #extracted_lines, $_;
}
truncate($fh->get_handle(), $fh->tell())
or die("Can't truncate $DataFile: $!\n");
This removes the first five lines of the data.txt file, stores them in another array and prints the removed lines on STDOUT:
use warnings;
use strict;
use Tie::File;
my $limit = 5;
my $DataFile = 'data.txt';
tie my #lines, 'Tie::File', $DataFile or die $!;
my #keeps = splice #lines, 0, $limit;
print "$_\n" for #keeps;
untie #lines;
I'm extremely new to programming in Perl, and new to the programming world in general.
I'm trying to write a program that opens a CSV file, reads it into an array, and parses through it using split().
Each field of the CSV file contains four things:
$full_name, $user_name, $password, $con_password
My problem is that I need to access the second element of each line (user_name). Then I need to put all the user names into an array so I can work with that.
I've done the split, but I don't know how to make sure I get the second element of each line.
This is what I have:
#!/usr/bin/perl
use CGI qw(:standard);
use strict;
use warnings;
print "Content-type: text/html\n\n";
my $file = '/home/2014/amosqu/public_html/cgi-bin/Members.csv';
open(my $csv, '>>', $file) or die "Could not open '$file' $!";
#i get these values from a form in an html file
my $full_name = param('full_name');
my $user_name = param('user_name');
my $password = param('password');
my $con_password = param('con_password');
#array to store user names
my #users = ();
while(my $lines = <$csv>) {
chomp $lines;
my #fields = split(/,/, $lines);
}
#access second element and put into #users ???
You would need to write something like this...
my #list;
open (my $csv, '<', $file) || die "cant open";
foreach (<$csv>) {
chomp;
my #fields = split(/\,/);
push #list, $fields[1];
}
In your code the file is opened for appending not reading.