I am not getting count of $mapA{$Brand_Name}->{Success} $mapA{$Brand_Name}->{Failure} please help on this actually i raised this problem in another question i.e closed so i am raising in this.
or any other way to increase the count for particular key.
#!/usr/bin/perl
use Text::CSV;
use POSIX qw(strftime);
use Data::Dumper;
use LWP::Simple;
my $APK_GCM="/root/Basavaraj/GCM/cdr_02-01-2018_StreamzGcm.csv";
my $WEB_GCM="/root/Basavaraj/GCM/cdr_02-01-2018_StreamzWebPushNotification.csv";
my $Yesterday= strftime ("%d-%m-%Y", localtime(time-86400));
my $Current_Date= strftime ("%d-%m-%Y",localtime(time));
print "$Yesterday \n";
print "$Current_Date \n";
open(STDOUT, '>', "/root/Basavaraj/STREAMZ_GCM_APK.txt");
#Creating Class to split the document line by line by comma ,
my $csv = Text::CSV->new({ sep_char => ',' });
open (my $data, '<:encoding(utf8)', $APK_GCM) or die "Could Not open File '$APK_GCM' $!\n";
open (my $data1,'<:encoding(utf8)', $WEB_GCM) or die "Could Not open File '$WEB_GCM' $!\n";
my %mapA;
my $dummyA =<$data>;
while (my $line = <$data>) {
if ($csv->parse($line)) {
my #fields = $csv->fields();
my $Brand_Name=$fields[2];
my $Streamz_Sent=$fields[5];
my $GoogleResA=$fields[5];
$mapA{$Brand_Name} = {Success =>0,Failure=> 0} unless exists ($mapA{$Brand_Name});
my $failureA='{error:MismatchSenderId}';
if ($GoogleResA eq $failureA){
$mapA{$Brand_Name}->{Failure}++;
print "$Brand_Name:$mapA{$Brand_Name}->{Failure} \n";
}else{
$mapA{$Brand_Name}->{Success}++;
print "$Brand_Name:$mapA{$Brand_Name}->{Success} \n";
}
} else {
warn "Line could not be parsed: $line\n";
}
}
#$, = ",";
print " $mapA{$Brand_Name}->{Failure} \n";
my $KeyA;
while (($keyA)=each (%mapA)){
my $success= $mapA{$Brand_Name}->{Success};
my $failure= $mapA{$Brand_Name}->{Failure};
print "$keyA $mapA{$Brand_Name}->{Failure}++ $mapA{$Brand_Name}->{Success}++ \n";
}
foreach my $name ( keys %mapA) {
print " $mapA{$Brand_Name}->{Failure} \n";
print " $mapA{$Brand_Name}->{Success} \n";
print "$name $mapA{$Brand_Name}->{Success} $mapA{$Brand_Name}->{Failure} \n";
}
Code looks messy and not clear, but i'm posting here the way to increment the count for this case, hope it will help someway, copy and paste the below program in your machine and try it out(demonstrates how to increment count, very similar to scenario mentioned above)
#!/usr/bin/perl
use strict;
use warnings;
my %results;
%results = ('Brand A' => {'Success' => 0, 'Failure' => 0},
'Brand B' => {'Success' => 1, 'Failure' => 1});
# add new entry into existing hash
#
$results{'Brand C'}{'Success'} = 5;
$results{'Brand C'}{'Failure'} = 6;
# increment Success count for specific brand straightaway
$results{'Brand B'}{'Success'}++;
print "Success count for brand B = $results{'Brand B'}{'Success'}\n";
#print out hash
#
# first key for example Brand A
for my $brand (keys %results)
{
print "Printing brand here: $brand-->";
# next key for example 'Success' or 'Failure'
#
for my $result (keys %{$results{$brand}})
{
#increment success or failure count
$results{$brand}{$result}++;
print "$result-->$results{$brand}{$result},";
}
print "\n";
}
Related
I am writing a Perl script which enables the addition and modification of parameters maintained in a particular file.
The script takes the following arguments; Parameter name($paraName), Parameter value($paraVal) and the file ($profile).
The script checks if the parameter($paraName) exists already. if it does, it just changes the value($paraVal) else adds both the parameter($paraName) and the value($paraVal) to the file($profile).
Following is the block of code for the same:
print " checking if parameter is already avaialable";
my $response = system("egrep -qs \"$paraName =\" $profile");
$rc = 1;
if ($response == 0) {
print " Parameter is already available, changing the value now! ";
$rc = system("sed -i 's:.*$paraName.*:$paraName = $paraVal \# Parameter changed by $script:' $profile");
print " Parameter $paraName has been updated with the value $paraVal in the Profile successfully \n\n";
}
else{
print " Parameter is not available, Adding the Paremeter now! ";
$rc = system("echo \"$paraName = $paraVal \# Parameter added by $script\" >> $profile");
print " Parameter $paraName has been added with the value $paraVal in the Profile successfully \n\n";
}
The script works fine for most cases, except when I have arguments with double quotes to be added as a new parameter. It works file for hash(#), slashes (), etc, when passes within a single quote(' ').
This is working in case of changing the value($paraVal) when the parameter($paraName) already exists. But while a new parameter has to be added, this fails to add double quotes in the parameter name.
Would appreciate some help here.
Here is an example of how you could write it as pure Perl:
use feature qw(say);
use strict;
use warnings;
my ( $paraName, $paraVal, $profile ) = #ARGV;
my $script = $0;
open ( my $fh, '<', $profile ) or die "Could not open file '$profile': $!";
my $found = 0;
while( my $line = <$fh> ) {
chomp $line;
if ( my ($key) = $line =~ /^(\Q$paraName\E)\s*=\s*/) {
say "$key = $paraVal \# Parameter changed by $script";
$found = 1;
}
else {
say $line;
}
}
close $fh;
if ( !$found ) {
say "$paraName = $paraVal \# Parameter added by $script";
}
Edit:
The above script does not modify the profile file, but instead writes the modified file to standard output. So it was meant to be used together with Shell redirection to save the output to a new file. To modify the profile file directly, you could use:
use feature qw(say);
use strict;
use warnings;
die "Bad arguments!" if #ARGV != 3;
my ( $paraName, $paraVal, $profile ) = #ARGV;
my $script = $0;
#ARGV = ( $profile );
$^I = '.bak';
my $found = 0;
while (my $line = <<>>) {
chomp $line;
if ( my ($key) = $line =~ /^(\Q$paraName\E)\s*=\s*/) {
say "$key = $paraVal \# Parameter changed by $script";
$found = 1;
}
else {
say $line;
}
} continue {
say "$paraName = $paraVal \# Parameter added by $script" if eof && !$found;
}
This will first save the original profile file to a backup file with .bak extension, and then overwrite the profile file with the modified content.
Try following code as alternative
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Pod::Usage;
use Getopt::Long;
use Data::Dumper;
my %opt; # program options
my %param; # parameters storage
my $fh; # file handle
GetOptions (
'file|f=s' => \$opt{file},
'name|n=s' => \$opt{name},
'value|v=s' => \$opt{value},
'operation|o=s' => \$opt{op},
'help|h' => \$opt{help},
'man|m' => \$opt{man},
'debug|d' => \$opt{debug}
) or pod2usage(1);
pod2usage(1) if $opt{help};
pod2usage(-exitval => 0, -versose => 2) if $opt{man};
pod2usage(1) unless $opt{file};
open $fh, "< $opt{file}"
or die "Couldn't open $opt{file}";
my #lines = <$fh>;
close $fh;
chomp #lines;
print Dumper(\#lines) if $opt{debug};
push #lines, "$opt{name} = $opt{value}"
if $opt{op} eq 'add';
#lines = map { /$opt{name}\s*=/ ? '' : $_ } #lines
if $opt{op} eq 'del';
#lines = map {
s/($opt{name})\s*=\s*(.*)/$1 = $opt{value}/; $_
} #lines if $opt{op} eq 'mod';
map{ say } #lines
if $opt{op} eq 'view';
map {
/$opt{name}\s*=\s*(.*)/ and say 'Verify: '
. ($1 eq $opt{value} ? 'ok' : 'no')
} #lines if $opt{op} eq 'check';
my %save = map { $_ => 1 } qw/add del mod/;
print Dumper(\#lines) if $opt{debug};
if( $save{ $opt{op} } ) {
open $fh, "> $opt{file}"
or die "Couldn't open $opt{file}";
map { say $fh $_ } #lines;
close $fh;
}
__END__
=head1 NAME
program - modify configuration file
=head1 SYNOPSIS
program [options] [file ...]
Usage:
program -op [add|del|mod|view|check] -n param -v value -f file
Options:
--file,-f configuration filename
--name,-n parameter name
--value,-v parameter value
--operation,-o operation to perform
--help,-h brief help message
--man,-m full documentation
--debug,-d debug mode
=head1 OPTIONS
=over 8
=item B<--file,-f>
Configuration file to edit
=item B<--name,-n>
Configuration parameter name to operate on
=item B<--value,-v>
Configuration parameter value to operate on
=item B<--operation,-o>
Operation to perform on parameter: add, del, mod, view, check
=item B<--debug,-d>
Debug flag to print debug messages.
=item B<--help,-h>
Print a brief help message and exits.
=item B<--man,-m>
Prints the manual page and exits.
=back
=head1 DESCRIPTION
B<This program> allows to operate on configuation files variables.
=head1 AUTHOR
B<Polar Bear> L<https://stackoverflow.com/users/12313309/polar-bear>
=cut
I have a function (a variation of string++):
sub inc
{
$_[0] =~ /^(.*?)([0-9]+)$/;
my ($a,$b)=($1,$2);
die "cannot increment [$_[0]]" unless defined $b;
warn "increment overflow [$_[0]]" if length(++$b) != length($2);
$a.$b;
}
It is invoked in many places of a script, on different data (sometimes from a file, sometimes from a database).
When I read from a filehandle, die and warn print a message like this:
cannot increment [abc] at script line 5, <filehandle> line 123.
otherwise a shorter message is printed:
cannot increment [abc] at script line 5.
When I read from database I would like to have a message like this:
cannot increment [abc] at script line 5, <SELECT...> line 123.
Is it possible?
Setting the line number is quite simple: an assignment to $. can be made. But how to set the 'filehandle' part and make it visible?
I have found such a workaround:
my $fh = "SELECT...";
open $fh, "/dev/null";
<$fh>;
but it is a bit long, and it actually does open a file.
The filehandle information that appears in warn and die messages is only set after calls to <HANDLE>, readline, tell, eof, and seek. When you fetch data from a database with DBI, for example, you're not calling any of these, so you have to pass the extra data yourself.
One way to do this is to write a custom exception class that stringifies to the text you want:
package MyException;
use strict;
use warnings 'all';
use v5.18.0;
use overload '""' => \&as_string;
sub new {
my ($self, $message, $src, $src_line) = #_;
my ($package, $file, $line) = caller;
if (! defined $src && ref ${^LAST_FH} eq 'GLOB') {
$src = *${^LAST_FH}{NAME};
$src_line = $.;
}
bless { message => $message,
file => $file,
line => $line,
src => $src,
src_line => $src_line }, $self;
}
sub as_string {
my ($self) = #_;
my $message = "$self->{message} at $self->{file} line $self->{line}";
if (defined $self->{src} && defined $self->{src_line}) {
$message .= ", <$self->{src}> line $self->{src_line}";
}
$message .= "\n";
}
1;
Note that Perl 5.18.0 or up is required to use the read-only ${^LAST_FH} variable, which holds a reference to the last read filehandle.
Here's how you would use this when reading from a file:
use strict;
use warnings 'all';
use MyException;
while (<DATA>) {
warn MyException->new('foo'); # equivalent to warn 'foo'
}
__DATA__
first
second
Output:
foo at ./myscript line 9, <DATA> line 1
foo at ./myscript line 9, <DATA> line 2
And here's how you would use it when fetching records from a database:
use strict;
use warnings 'all';
use DBI;
use MyException;
my $dbh = DBI->connect('dbi:mysql:test', 'user', 'pass', {
RaiseError => 1
});
my $sql = 'SELECT * FROM test';
my $sth = $dbh->prepare($sql);
$sth->execute;
my $count;
while (my $row = $sth->fetch) {
warn MyException->new('foo', $sql, ++$count);
}
Output:
foo at ./myscript line 19, <SELECT * FROM test> line 1
foo at ./myscript line 19, <SELECT * FROM test> line 2
(Unfortunately, DBI doesn't provide a method to get the number of rows that have been fetched so far, so you have to count them yourself.)
Since you're trying to warn or die from inside a subroutine, you have to do a little bit more work. The simplest approach for die would be to trap exceptions from your subroutine with eval and re-throw them:
my $count = 1;
while (my $row = $sth->fetch) {
eval {
inc($row[0]);
};
if ($# =~ /^(cannot increment \[.*?\])/) {
die MyException->new($1, $sql, $count);
}
elsif ($#) {
die $#;
}
$count++;
}
You can handle warnings in a similar way by creating a __WARN__ handler:
{
my $count = 1;
local $SIG{__WARN__} = sub {
if ($_[0] =~ /^(increment overflow \[.*?\])/) {
warn MyException->new($1, $sql, $count);
}
else {
warn #_;
}
};
while (my $row = $sth->fetch) {
inc($row[0]);
$count++;
}
}
You may prefer this implementation of your inc subroutine. Your own uses the reserved variables $a and $b, as well as saving and retrieving the initial non-numeric part of the string
Note that the STDERR output is not in sync with STDOUT, so the warning appears prematurely in the aggregated text. In reality the warning is issued only when the passed string has an all-nines numeric field
use strict;
use warnings 'all';
my $s = 'ZZ90';
for ( 1 .. 20 ) {
$s = inc_str($s);
print $s, "\n";
}
sub inc_str {
my ($str) = #_;
$str =~ s{([0-9]+)$}{
my $num = $1;
warn "Increment overflow [$str]" unless $num =~ /[^9]/;
sprintf '%0*d', length($num), $num+1;
}e or die "Cannot increment [$str]";
return $str;
}
output
Increment overflow [ZZ99] at E:\Perl\source\inc_str.pl line 18.
ZZ91
ZZ92
ZZ93
ZZ94
ZZ95
ZZ96
ZZ97
ZZ98
ZZ99
ZZ100
ZZ101
ZZ102
ZZ103
ZZ104
ZZ105
ZZ106
ZZ107
ZZ108
ZZ109
ZZ110
I'm using two text files sampleA.txt and sampleB.txt. I have two fields in each file and I need to compare first record(first row) of sampleA.txt with the first row of sampleB.txt and I want to show matching records as well as miss matching records in command prompt.I need to do that in Perl.
Using the below script I'm getting one output but it is wrong. I need to populate both matching as well as mismatching. How to do that?
sampleA.txt:
1|X
2|A
4|Z
5|A
sampleB.txt:
2|A
2|X
3|B
4|C
Output I'm getting:
2|A
2|X
4|C
Outputs I want:
Matching-Output:
2|A
Miss-matching-Output:
1|X
4|Z
5|A
3|B
4|C
Perl Script:
#!/usr/bin/perl
use strict;
use warnings;
open(FILE1,'C:\Users\sathiya.kumar\Desktop\sampleA.txt') || die $!;
open(FILE2,'C:\Users\sathiya.kumar\Desktop\sampleB.txt') || die $!;
my $interline;
while (my $line= <FILE1>) {
my #fields = split('\|',$line);
parser($fields[0]);
}
sub parser {
my $mergeid = shift;
while (defined $interline || ($interline= <FILE2>)) {
my #fields = split('\|',$interline);
my $key = $fields[0];
if ($key lt $mergeid) {
# Skip non-matching records
$interline = undef;
next;
} elsif ($key gt $mergeid) {
# wait for next key
last;
} else {
print $interline;
$interline = undef;
}
}
}
close(FILE1);
close(FILE2);
Let me know if you need more information.
You left out 2|X:
use strict;
use warnings;
use 5.016;
use Data::Dumper;
#Create a set from the entries in sampleA.txt:
my $fname = 'sampleA.txt';
open my $A_INFILE, '<', $fname
or die "Couldn't open $fname: $!";
my %a;
while (my $line = <$A_INFILE>) {
chomp $line;
$a{$line} = undef;
}
close $A_INFILE;
say Dumper(\%a);
#Create a set from the entries in sampleB.txt:
$fname = 'sampleB.txt';
open my $B_INFILE, '<', $fname
or die "Couldn't open $fname: $!";
my %b;
while (my $line = <$B_INFILE>) {
chomp $line;
$b{$line} = undef;
}
close $B_INFILE;
say Dumper(\%b);
#Divide the entries in both files into matches and mismatches:
my (#matches, #mismatches);
for my $a_val (keys %a) {
if (exists $b{$a_val}) {
push #matches, $a_val;
}
else {
push #mismatches, $a_val;
}
}
for my $b_val (keys %b) {
if (not exists $a{$b_val}) {
push #mismatches, $b_val;
}
}
say Dumper(\#matches);
say Dumper(\#mismatches);
--output:--
$VAR1 = {
'5|A' => undef,
'4|Z' => undef,
'1|X' => undef,
'2|A' => undef
};
$VAR1 = {
'2|X' => undef,
'3|B' => undef,
'4|C' => undef,
'2|A' => undef
};
$VAR1 = [
'2|A'
];
$VAR1 = [
'5|A',
'4|Z',
'1|X',
'2|X',
'3|B',
'4|C'
];
If you evaluate a hash in scalar context, it returns false if the hash is empty. If there are any key/value pairs, it returns true; more precisely, the value returned is a string consisting of the number of used buckets and the number of allocated buckets, separated by a slash. This is pretty much useful only to find out whether Perl's internal hashing algorithm is performing poorly on your data set. For example, you stick 10,000 things in a hash, but evaluating %HASH in scalar context reveals "1/16" , which means only one out of sixteen buckets has been touched, and presumably contains all 10,000 of your items. This isn't supposed to happen. If a tied hash is evaluated in scalar context, the SCALAR method is called (with a fallback to FIRSTKEY ).
http://perldoc.perl.org/perldata.html
I'm trying to create an array of hashes in perl and I'm having some trouble in printing it as the only thing that prints out is the last hash entered.
Is there something wrong in how I push the hashtables into the array? Also, how can I print the contents of the array (the hashtables) properly?
print "\n===========SUBJECTS===========\n";
my $exit = "n";
until ( $exit eq "y" ) { #loops until user enters 'y'
print "Course Number: ";
my $cNum = <STDIN>;
chomp($cNum);
print "Course Credit: ";
my $cCred = <STDIN>;
print "Grade: ";
my $cGrade = <STDIN>;
%subHash = (
"courseNumber" => $cNum,
"courseCredit" => $cCred,
"courseGrade" => $cGrade,
);
push #subList, \%subHash;
$subCount += 1;
print "\nFinished adding subjects?\n[y/n]\nCHOICE: "; #asks for subject input termination
$exit = <STDIN>;
chomp($exit);
print "\n==============================\n";
}
You'll need to loop through the array of hash refs, dereferencing each one appropriately.
for my $hash_ref (#AoH)
{
for my $key (keys %{$hash_ref})
{
print "$key => $hash_ref->{$key}\n"
}
}
or
for my $hash_ref (#AoH)
{
while (my ($key, $val) = each %{$hash_ref})
{
print "$key => $val\n";
}
}
See perldoc perldsc for more about nested data structures, including printing them out.
The answer has already been given to you. Are you having trouble copy and pasting it into your homework?
use strict;
use warnings;
my #subList;
print "\n===========SUBJECTS===========\n";
my $exit = "n";
until ( $exit eq "y" ) { #loops until user enters 'y'
print "Course Number: ";
my $cNum = <STDIN>;
chomp($cNum);
print "Course Credit: ";
my $cCred = <STDIN>;
chomp($cCred);
print "Grade: ";
my $cGrade = <STDIN>;
chomp($cGrade);
push #subList, {
"courseNumber" => $cNum,
"courseCredit" => $cCred,
"courseGrade" => $cGrade,
};
print "\nFinished adding subjects?\n[y/n]\nCHOICE: "; #asks for subject input termination
$exit = <STDIN>;
chomp($exit);
print "\n==============================\n";
}
foreach my $hashref ( #subList ) {
while ( my ($key, $val) = each %{$hashref} ) {
print "$key => $val\n";
}
print "-----\n";
}
In my sms-script I read in the text to send with this subroutine:
my $input = input( "Enter the input: " );
sub input {
my $arg = shift;
print $arg if $arg;
print "\n ";
chomp( my $in = <> );
return $in;
}
This way I can correct errors only through canceling all until I reach the error and this only in the last line.
Is there a better way to read in my text?
This is the "normal" way to read input:
use strict;
use warnings;
# ...
while (my $input = <>)
{
chomp $input;
handle_error($input), next unless validate($input);
# do something else with $input...
}
You can use a while loop inside your input subroutine, e.g.
my $is_valid = 0;
my $input;
while (!$is_valid) {
print "Enter something: ";
$input = <>;
$is_valid = validate_input($input);
}