Printing an array variable displaying all its elements using main:: . - arrays

The #main::match_to_array prints out only the last element in the array #match_to_array , not the whole array.
I did my code with reference to this SO link.
The input HTML consists of
dmit#sp.com
ems#es.com
dew#es.com
dmit#sp.com
erg#es.com
#!/usr/bin/perl –w
use strict;
use warnings;
use Cwd;
sub extractMail {
my $perl_path = cwd;
# Full HTML.htm
if(-e 'test.html') {
open(OPENFILE, "$perl_path/test.html") or die "Unable to open file";
}
my #email = <OPENFILE>;
close OPENFILE;
foreach my $email (#email){
if ($email =~ /regex to match data/{
my $match = "$1\n";
our #match_to_array = split ("\n",$match);
} # end of if statement
} # end of foreach
} # end of subroutine extractMail
for (my $a = 1;$a<=1;$a++){
&extractMail;
print #main::match_to_array;
}

You have misunderstood the post. The point is to declare the variable at the right place. In this case, you should probably return the value from the subroutine. Moreover, by assigning to an array
#match_to_array = split /\n/, $match;
you are overwriting the previous contents of the array. Use push instead.
Untested:
#!/usr/bin/perl –w
use strict;
use warnings;
use Cwd;
sub extractMail {
my $perl_path = cwd;
if (-e 'test.html') {
open my $OPENFILE, "$perl_path/test.html" or die "Unable to open file: $!";
}
my #match_to_array;
while (my $email = <$OPENFILE>) {
if ($email =~ /regex to match data/) {
my $match = "$1\n";
push #match_to_array, split /\n/, $match;
}
}
return #match_to_array;
}
for my $i (1 .. 1) {
my #match_to_array = extractMail();
print "#match_to_array\n";
}

my #email = <OPENFILE>;
close OPENFILE;
This might be the Problem, after those lines #email is containg one element, namely "dmit#sp.com ems#es.com ...".
Afterwards you're doing this:
foreach my $email (#email)
This will loop once, with
$email = "dmit#sp.com ems#es.com ..."
Then your regex removes everything BUT "dmit#sp.com" and leads you to the conclusion that only one element of your list is processed.
Try reading up on split to generate an array out of your space-separated list

Related

Parse a CSV into Perl hash in a sub and return the value passed to that sub

I try to parse a csv into hash in perl in a sub, then return value of key passed to sub as an argument. CSV file is like:
host1, 12121
host2, 34324252345
host3, 45345
host4, 56363425
host5, 3.1
hostn, 435345
And my code is like:
#!/usr/bin/perl -w
my $host_key = getValue('host1');
print $host_key;
sub getValue {
my $host_file = 'test.csv';
my $hostname = $_[0];
chomp($hostname);
my %hash;
open my $fh, '<', $host_file or die "Cannot open: $!";
while (my $line = <$fh>) {
my #hostname_lines = split /,/, $line;
my $hostname = shift #hostname_lines;
$hash{$hostname} = \#hostname_lines;
}
close $fh;
my $host_value = $hash{$hostname};
return $host_value;
}
When I run this code, my return value would be ARRAY(0x6b72d0) but I expect a return value of 12121
You build a hash with values being arrayrefs inside the while loop.
So you need to retrieve an element in that arrayref
my %host;
...
my $host_value = $host{$name}->[0];
what can also be written as
my $host_value = $host{$name}[0];
where the original array had been shifted so the number is now the first element in arrayref.
This can also be done as
while (my $line = <$fh>) {
my ($name, #numbers) = split /\s*,\s*/, $line;
$host{$name} = \#numbers;
}
since the first element in split's return list goes into the first scalar, and the rest into the array.
The data shows one number for a host on each line. If that is always so, no need for an arrayref
my %host;
while (my $line = <$fh>) {
my ($name, $val) = split /\s*,\s*/, $line;
$host{$name} = $val;
}
where /\s*,\s*/ trims spaces as well, or even
my %host = map { split /\s*,\s*/ } <$fh>;
which has the weakness of not being able to easily check expected data format.

Perl: How to reference to an array?

I have a program here that will allow user to enter in words that will be used as filenames later on. The user's input is inserted into an array. I then create a simple menu asking what the user wants to do with the "filename": create, reame, copy, and delete. Using subroutines, I believe I've successfully executed the code. However, I am having trouble trying to reference the array element.
In short, how do I create, rename, copy, and delete the filenames that are saved in the array? The issues I cant resolve are asterisked
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy qw/copy/;
my $new;
my $old;
my $file;
print "Enter number of lines\n";
chomp(my $n = <STDIN>);
my #lines;
print "Enter some words!\n";
for (1..$n) {
chomp(my $input = <STDIN>);
#will add the user input at the beginning of the array
push #lines, $input;
}
print "#lines\n";
#create a menu
my $in = '';
print "1. Create\n2. Rename\n3. Copy\n4. Delete\n5. Quit\n";
while ($in ne "quit")
{
print "\nEnter the your choice:\n";
chomp($in = <STDIN>);
print "For which file do you want to $in?\n";
print "#lines\n";
**#I need to reference the array here***********************
if ($in eq "create") {
***How to create the file that the user inputted?*****************
&createFile;
print "\nFile has been created\n";
}
elsif ($in eq "rename") {
#print "Enter the old name\n";
# chomp($old = <STDIN>);
#*********refer to array of FILES*********************
print "Enter the new name for this file!\n";
chomp($new = <STDIN>);
&renameFile;
print "File has successfully been renamed.";
}
elsif ($in eq "copy") {
#********file and array refering***************************
&copyFile;
print "Hopefully, the file has beed copied!";
}
elsif ($in eq "delete") {
#******refer to file from user*******************
&deleteFile;
print "Deleted";
}
}
#create subroutine
sub createFile {
open('>' .*****issue here too**) or die "\nCannot create";
}
sub renameFile {
rename ($old, $new);
}
sub copyFile {
copy $old, $new;
}
sub deleteFile {
#unlink *****************************
}
First line is $line[0], second is $line[1] and so on...
You can get user choice like this:
$line[$in]
About how to refer to perl data structures see here
$lines[0]; #First line
$lines[1]; #Second line
$array = \#lines; # Get reference to the list of lines
$array->[0]; #First line
$array->[1]; #Second line
to create file and put data into just use:
open $fh, '>filename';
print $fh #lines;
print $fh #$array; # ... or same for reference
Notice lack of coma after $fh

How to create multiple arrays at once in perl

I'm trying to create 23 arrays without typing out #array1, #array2, and so on, and load them each with the variables from the array #r if the $chrid matches the array number (if $chrid=1 it should be placed in #array1). How can I achieve this?
Here is what I have so far:
#!/usr/bin/perl
use warnings;
use strict;
my #chr;
my $input;
open ($input, "$ARGV[0]") || die;
while (<$input>) {
my #r = split(/\t/);
my $snps = $r[0];
my $pval = $r[1];
my $pmid = $r[2];
my $chrpos = $r[3];
my $chrid = $r[4];
for ($chrid) {
push (#chr, $chrid);
}
}
close $input;
You can use an array of arrays, where each subarray is stored at a sequentially increasing index in your array of arrays. Here is what that could look like, but it is still unclear to me what you want data you want to store:
use warnings;
use strict;
my #chr;
open my $input_fh, '<', $ARGV[0]
or die "Unable to open $ARGV[0] for reading: $!";
while (< $input_fh> ) {
# you can unpack your data in a single statement
my ($snps, $pval, $pmid, $chrpos, $chrid) = split /\t/;
# unclear what you actually want to store
push #{ $chr[$chrid] }, ( $snps, $pval, $pmid, $chrpos, $chrid );
}
close $input_fh;

Compare two hashes in perl and list which records are extra?

I have two text files that contain user records. I have to compare these two files and figure out which users are missing from File1. And delete these Orphans from file2.
#!/usr/local/bin/perl -w
use strict;
use warnings;
use autodie;
use Text::Diff;
use List::Compare;
use Data::Dumper;
my $Users1 = "Users1.txt";
my $Users2 ="Users2.txt";
my %hash1;
my %hash2;
my %new_hash;
my #sorted_1;
my #sorted_2;
my #list_keys1;
my #list_keys2;
open(my $fh1, '<:encoding(UTF-8)', $Users1) or die "Colud not open the file!";
while(my $record1 = <$fh1>)
{
chomp $record1;
my #list1 = split( '/', $record1);
foreach my $item(#list1)
{
$new_hash{$list1[1]} = $list1[0];
$hash1{$list1[1]} = $list1[0];
}
while ( my ($key, $value) = each(%hash1) ) {
push (#list_keys1, $key);
#sorted_1 = sort #list_keys1;
}
}
print "\t\tHash values for USERS1:\n";
print Dumper \%hash1;
open(my $fh2, '<:encoding(UTF-8)', $Users2) or die "Colud not open the file!";
while(my $record2 = <$fh2>)
{
chomp $record2;
my #list2 = split( '/', $record2);
foreach my $item(#list2)
{
$hash2{$list2[1]} = $list2[0];
}
while ( my ($key, $value) = each(%hash2) )
{
push (#list_keys2, $key);
#sorted_2 = sort #list_keys2;
}
}
print "\n\n\t\tHash values for Users2:\n";
print Dumper \%hash2;
#hash1{#list_keys1} = 1;
#hash2{#list_keys2} = 1;
foreach(keys %hash2)
{
print "\nThis user does not exist(to be deleted): $_\n" unless exists $hash1{$_};
}
foreach (keys %hash1)
{
print "\nNew User (to be added):$_\n" unless exists $hash2{$_};
}
close ($fh1);
close ($fh2);
Questions:
I am not able to sort the user ID (String) alphabetically(here, USER IDs are random strings of length 7). Is there any limitations when it comes to sorting array/hashes in Perl?
I am not able to compare two hashes and get the differences. What would be the most efficient way to do that?
Are there any additional libraries that I need to install in order to handle this part of code?
Sample records from file:
File1:
ASIA/ASEDF46
INDIA/PSDfT5V
CHINA/FSDfT5V
INDIA/AA44TYB
USA/BBRTT67
File 2:
INDIA/PSDfT5V
CHINA/FSDfT5V
INDIA/AA44TYB
USA/BBRTT67
UK/ZK9EELO
use strict;
use warnings;
use autodie;
open my $in, '<', 'in.txt';
open my $in2, '<', 'in_2.txt';
my (%data1, %data2);
while(<$in>){
chomp;
my #split = split/\//;
$data1{$split[0]} = $split[1];
}
while(<$in2>){
chomp;
my #split = split/\//;
$data2{$split[0]} = $split[1];
}
foreach(sort keys %data1){
print "User: $_ Value: $data1{$_}\n" if $data2{$_};
}

grepping command line arguments out of an array in perl

I have a file that looks like this:
[options42BuySide]
logged-check-times=06:01:00
logged-check-address=192.168.3.4
logged-check-reply=192.168.2.5
logged-check-vac-days=sat,sun
start-time=06:01:00
stop-time=19:00:00
falldown=logwrite after 10000
failtolog=logwrite after 10000
listento=all
global-search-text=Target Down. This message is stored;
[stock42BuySide]
logged-check-times=06:01:00
logged-check-address=192.168.2.13
logged-check-reply=192.168.2.54
logged-check-vac-days=sat,sun
start-time=06:01:00
stop-time=18:00:00
The script grinds the list down to just the name, start and stop time.
sellSide40, start-time=07:05:00, stop-time=17:59:00
SellSide42, start-time=07:06:00, stop-time=17:29:00
SellSide44, start-time=07:31:00, stop-time=16:55:00
42SellSide, start-time=09:01:00, stop-time=16:59:00
The problem is that I would like to filter out specific names from the file with comand line parameters.
I am trying to use the #ARGV array and grep the command line values out of the #nametimes array. Something like :
capser#capser$ ./get_start_stop SorosSellSide42 ETFBuySide42
The script works fine for parsing the file - I just need help on the command line array
#!/usr/bin/perl
use strict ;
use warnings ;
my ($name , $start, $stop, $specific);
my #nametimes;
my $inifile = "/var/log/Alert.ini";
open ( my $FILE, '<', "$inifile") or die ("could not open the file -- $!");
while(<$FILE>) {
chomp ;
if (/\[(\w+)\]/) {
$name = $1;
} elsif (/(start-time=\d+:\d+:\d+)/) {
$start = $1;
} elsif (/(stop-time=\d+:\d+:\d+)/) {
$stop = $1;
push (#nametimes, "$name, $start, $stop");
}
}
for ($a = 0; $a >= $#ARGV ; $a++) {
$specific = (grep /$ARGV[$a]/, #nametimes) ;
print "$specific\n";
}
It is probably pretty easy - however I have worked on it for days, and I am the only guy that uses perl in this shop. I don't have anyone to ask and the googlize is not panning out. I apologize in advance for angering the perl deities who are sure to yell at me for asking such and easy question.
Your construct for looping over #ARGV is a bit unwieldy - the more common way of doing that would be:
for my $name (#ARGV) {
#do something
}
But really, you don't even need to loop over it. You can just join them all directly into a single regular expression:
my $names = join("|", #ARGV);
my #matches = grep { /\b($names)\b/ } #nametimes;
I've used \b in the regex here - that indicates a word boundary, so the argument SellSide4 wouldn't match SellSide42. That may or may not be what you want...
Use an array to store the results from the grep(), not a scalar. Push them, not assign. Otherwise the second iteration of the for loop will overwrite results. Something like:
for my $el ( #ARGV ) {
push #specific, grep { /$el/ } #nametimes);
};
print join "\n", #specific;
The easiest thing to do is to store your INI file as a structure. Then, you can go through your structure and pull out what you want. The simplest structure would be a hash of hashes. Where your heading is the key to the outer hash, and the inner hash is keyed by the parameter:
Here's is creating the basic structure:
use warnings;
use strict;
use autodie;
use feature qw(say);
use Data::Dumper;
use constant INI_FILE => "test.file.txt";
open my $ini_fh, "<", INI_FILE;
my %ini_file;
my $heading;
while ( my $line = <$ini_fh> ) {
chomp $line;
if ( $line =~ /\[(.*)\]/ ) { #Headhing name
$heading = $1;
}
elsif ( $line =~ /(.+?)\s*=\s*(.+)/ ) {
my $parameter = $1;
my $value = $2;
$ini_file{$heading}->{$parameter} = $value;
}
else {
say "Invalid line $. - $line";
}
}
After this, the structure will look like this:
$VAR1 = {
'options42BuySide' => {
'stop-time' => '19:00:00',
'listento' => 'all',
'logged-check-reply' => '192.168.2.5',
'logged-check-vac-days' => 'sat,sun',
'falldown' => 'logwrite after 10000',
'start-time' => '06:01:00',
'logged-check-address' => '192.168.3.4',
'logged-check-times' => '06:01:00',
'failtolog' => 'logwrite after 10000',
'global-search-text' => 'Target Down. This message is stored;'
},
'stock42BuySide' => {
'stop-time' => '18:00:00',
'start-time' => '06:01:00',
'logged-check-reply' => '192.168.2.54',
'logged-check-address' => '192.168.2.13',
'logged-check-vac-days' => 'sat,sun',
'logged-check-times' => '06:01:00'
}
};
Now, all you have to do is parse your structure and pull the information you want out of it:
for my $heading ( sort keys %ini_file ) {
say "$heading " . $ini_file{$heading}->{"start-time"} . " " . $ini_file{$heading}->{"stop-time"};
}
You could easily modify this last loop to skip the headings you want, or to print out the exact parameters you want.
I would also recommend using Getopt::Long to parse your command line parameters:
my_file -include SorosSellSide42 -include ETFBuySide42 -param start-time -param stop-time
Getopt::Long could store your parameters in arrays. For example. It would put all the -include parameters in an #includes array and all the -param parameters in an #parameters array:
for my $heading ( #includes ) {
print "$heading ";
for my $parameter ( #parameters ) {
print "$ini_file{$heading}->{$parameter} . " ";
}
print "\n;
}
Of course, there needs to be lots of error checking (does the heading exist? What about the requested parameters?). But, this is the basic structure. Unless your file is extremely long, this is probably the easiest way to process it. If your file is extremely long, you could use the #includes and #parameters in the first loop as you read in the parameters and headings.

Resources