I have a file with many rows, all of which look like this:
name:country:stuff:stuff
What I'm trying to do is print only the name for that row if the country matches what the user entered. I can not get this to work with the STDIN, it only works if I assign a value to the string that matches.
For example, if I put $country = "USA"; it'll show the name of everyone from the USA, but if I put
$country =< STDIN>; and enter country when I'm prompted to it doesn't work. Here is what I have so far.
system ("clear");
print ("Please enter a country\n");
open (players, "playerFile");
while (<players>) {
chomp();
#fields = split(':', $_);
$country = <STDIN>;
chomp ($country);
if ($fields[1] eq $country) {
print "$fields[0]\n";
}
}
Can someone let me know what I'm doing wrong? I've been stuck on this for probably two hours. Thanks.
Here are some lines in the playerFile
Roger Federer:Switzerland:6
Stan Warinka:Switzerland:2
Novak Djokovic:Serbia:3
Ryan Harrison:USA
Andy Murray:Great Britain:4
David Ferrer:Spain:2
J M Del Potro:Argentina:3
Thomas Berdych:Czech Republic:2
This works for me:
use strict;
use warnings;
print ("Please enter a country\n");
my $country = <STDIN>;
chomp($country);
open (my $players, "<", "playerFile") || die "No playerfile found";
while (<$players>) {
chomp;
my #fields = split(':', $_);
print "fields[0]\n" if ($fields[1] eq $country);
}
Looks like you need to move your country input outside of your loop.
Like this ....
use strict;
use warnings;
system ("clear");
print ("Please enter a country\n");
open (playerfile, "playerFile") || die "No playerfile found";
my $country = <STDIN>; # Get the country.
chomp($country);
while (<playerfile>) {
chomp;
my #fields = split(':', $_);
if ($fields[1] eq $country) {
print "$fields[0]\n";
}
}
Related
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";
}
I am using split function to extract the a string from given line.
exp :
\abc\Logs\PostBootLogs\05-27-2014_17-05-51\UILogs_05-27-2014_17-05-52.txt
\abc\Logs\PostBootLogs\01-10-1970_20-33-22\01-10-1970_21-18-26\UILogs_01-10-1970_21-18-27.txt
In the above exp we need to capture string which is there between PostBootLogs and UILogs_01-10-1970_21-18-27.txt
Code :
use strict;
use warnings;
my $data = '\abc\Logs\PostBootLogs\05-27-2014_17-05-51\UILogs_05-27-2014_17-05-52.txt';
my $test1 = '\abc\Logs\PostBootLogs\01-10-1970_20-33-22\01-10-1970_21-18-26\UILogs_01-10-1970_21-18-27.txt';
my #values = split('UILogs'(split('PostBootLogs', $data)));
my #values1 = split('UILogs', $values[1]);
print "$values1[0]\n\n";
print "$test1\n\n";
my #values_1= split('PostBootLogs', $test1);
my #values1_1 = split('UILogs', $values_1[1]);
print $values1_1[0];
exit 0;
is there any better way to do this thing?
You can use regex to capture between PostBootLogs\ and \UILogs
my ($captured) = $data =~ /PostBootLogs\\ (.+?) \\UILogs/x;
Regular expressions make this sort of thing much easier.
$data =~ m/PostBootLogs(.*?)UILogs/ or die "Misformatted data";
my $timestamps = $1;
Creative use of splits. As has been demonstrated, the easiest method to do this is to use a regex.
However, if you want to see how to use splits to more cleanly accomplish this observe the following:
use strict;
use warnings;
my #data = qw(
\abc\Logs\PostBootLogs\05-27-2014_17-05-51\UILogs_05-27-2014_17-05-52.txt
\abc\Logs\PostBootLogs\01-10-1970_20-33-22\01-10-1970_21-18-26\UILogs_01-10-1970_21-18-27.txt
);
print "splits: \n";
for (#data) {
my ($vol, #path) = split /\\/;
my $subdir = join '\\', #path[3..$#path-1];
print $subdir, "\n";
}
print "regex: \n";
for (#data) {
if (/PostBootLogs\\(.*)\\UILogs/) {
print "$1\n";
} else {
warn "Data format not recognized: $_";
}
}
Outputs:
splits:
05-27-2014_17-05-51
01-10-1970_20-33-22\01-10-1970_21-18-26
regex:
05-27-2014_17-05-51
01-10-1970_20-33-22\01-10-1970_21-18-26
I want to make a tool to classify each line in input file to several files
but it seems have some problem in naming a filehandler so I can't go ahead , how do I solve?
here is my program
ARGV[0] is the input file
ARGV[1] is the number of classes
#!/usr/bin/perl
use POSIX;
use warnings;
# open input file
open(Raw,"<","./$ARGV[0]") or die "Can't open $ARGV[0] \n";
# create a directory class to store class files
system("mkdir","Class");
# create files for store class informations
for($i=1;$i<=$ARGV[1];$i++)
{
# it seems something wrong in here
open("Class$i",">","./Class/$i.class") or die "Can't create $i.class \n";
}
# read each line and random decide which class to store
while( eof(Raw) != 1)
{
$Line = readline(*Raw);
$Random_num = ceil(rand $ARGV[1]);
for($k=1;$k<=$ARGV[1];$k++)
{
if($Random_num == $k)
{
# Store to the file
print "Class$k" $Line;
last;
}
}
}
for($h=1;$h<=$ARGV[1];$h++)
{
close "Class$h";
}
close Raw;
thanks
Later I use the advice provided by Bill Ruppert
I put the name of filehandler into array , but it seems appear a syntax bug , but I can't correct it
I label the syntax bug with ######## A syntax error but it looks quite OK ########
here is my code
#!/usr/bin/perl
use POSIX;
use warnings;
use Data::Dumper;
# open input file
open(Raw,"<","./$ARGV[0]") or die "Can't open $ARGV[0] \n";
# create a directory class to store class files
system("mkdir","Class");
# put the name of hilehandler into array
for($i=0;$i<$ARGV[1];$i++)
{
push(#Name,("Class".$i));
}
# create files of classes
for($i=0;$i<=$#Name;$i++)
{
$I = ($i+1);
open($Name[$i],">","./Class/$I.class") or die "Can't create $I.class \n";
}
# read each line and random decide which class to store
while( eof(Raw) != 1)
{
$Line = readline(*Raw);
$Random_num = ceil(rand $ARGV[1]);
for($k=0;$k<=$#Name;$k++)
{
if($Random_num == ($k+1))
{
print $Name[$k] $Line; ######## A syntax error but it looks quite OK ########
last;
}
}
}
for($h=0;$h<=$#Name;$h++)
{
close $Name[$h];
}
close Raw;
thanks
To quote the Perl documentation on the print function:
If you're storing handles in an array or hash, or in general whenever you're using any expression more complex than a bareword handle or a plain, unsubscripted scalar variable to retrieve it, you will have to use a block returning the filehandle value instead, in which case the LIST may not be omitted:
print { $files[$i] } "stuff\n";
print { $OK ? STDOUT : STDERR } "stuff\n";
Thus, print $Name[$k] $Line; needs to be changed to print { $Name[$k] } $Line;.
How about this one:
#! /usr/bin/perl -w
use strict;
use POSIX;
my $input_file = shift;
my $file_count = shift;
my %hash;
open(INPUT, "<$input_file") || die "Can't open file $input_file";
while(my $line = <INPUT>) {
my $num = ceil(rand($file_count));
$hash{$num} .= $line
}
foreach my $i (1..$file_count) {
open(OUTPUT, ">$i.txt") || die "Can't open file $i.txt";
print OUTPUT $hash{$i};
close OUTPUT;
}
close INPUT;
I wonder if any module exist that can automate file numbering process.
If i try open "foo.bar" and it exists i open "foo_1.bar" without race condition.
What if two apps try open some file. Open fail or they get filehandles with diferent number?
Very thx for help.
I don't know of a canned module to do this off the top of my head, but the basic idea if you want a sequential file name is:
use Fcntl;
use Errno;
$seq = "";
until (defined ($fh = sysopen("foo".$seq.".bar", O_WRONLY|O_CREAT|O_EXCL, 0600))) {
last if $! != EEXIST;
$seq eq '' && $seq = '_0';
$seq =~ s/(\d+)/$1 + 1/e;
}
# if !defined $fh then $! contains the error, otherwise "foo".$seq.".bar" is created
Opens unique file name for writing. Return array ref to IO::File ref and writing name.
If fail return undef. Work with warnings and strict.
use Fcntl;
use Errno;
use IO::File;
sub open_unique {
my $file = shift || '';
unless ($file =~ /^(.*?)(\.[^\.]+)$/) {
print "Bad file name: '$file'\n";
return;
}
my $io;
my $seq = '';
my $base = $1;
my $ext = $2;
until (defined ($io = IO::File->new($base.$seq.$ext
,O_WRONLY|O_CREAT|O_EXCL))) {
last unless $!{EEXIST};
$seq = '_0' if $seq eq '';
$seq =~ s/(\d+)/$1 + 1/e;
}
return [$io,$base.$seq.$ext] if defined $io;
}
You might want to look at File::Temp.
Something like:
($fh, $filename) = tempfile('foo_XXXX', SUFFIX => '.bar');
print $fh "Some data\n";
close($fh) or die;
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);
}