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);
}
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 making a score-keeping script in Perl, and would like to have it ask how many players there are, and ask for a name, then score, for each player. I have a good bit of this script done, but only for 3 players. the current script can be found on github here: skore
(from link:)
#!/usr/bin/env perl
use strict;
my $version = "1.0";
my $arg = shift(#ARGV);
my $subname = $arg;
if (!defined($arg)){
cmd_go();
}
$subname =~ s/-/_/g;
my $sub = main->can("cmd_$subname") || main->can("dev_$subname") || main->can("hid_$subname");
if (!defined($sub))
{
print STDERR "Invalid command given.\nUse \e[1;32m./skore help\e[0m for a list of commands.\n";
exit 1;
}
else
{
$sub->(#ARGV);
exit 0;
}
# Main command
sub cmd_go()
{
print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
print "••••••••••••••••••••\n";
print "• Welcome to \e[1;32mskore\e[0m •\n";
print "••••••••••••••••••••\n\n";
my #game = prompt("What game are we scoring?\n");
print "••• Game name locked: #game\n\n";
my #p1name = prompt("Player 1 name?\n");
my #p2name = prompt("Player 2 name?\n");
my #p3name = prompt("Player 3 name?\n");
print "\n";
print "••• Player names locked: #p1name #p2name #p3name\n\n";
my #p1score = prompt_num("score for #p1name?\n");
my #p2score = prompt_num("score for #p2name?\n");
my #p3score = prompt_num("score for #p3name?\n");
print "\n";
print "••• Game: #game\n";
print "••• #p1name\n";
print "••••• \e[1;32m#p1score\e[0m\n";
print "••• #p2name\n";
print "••••• \e[1;32m#p2score\e[0m\n";
print "••• #p3name\n";
print "••••• \e[1;32m#p3score\e[0m\n";
exit 1;
}
sub cmd_help()
{
print "To get right into using skore, simply type ./skore\n";
print "For details about skore, such as version, use ./skore pkg\n";
}
sub cmd_pkg()
{
print "skore version: $version\n";
print "Detected OS: ";
exec "uname -r";
}
sub prompt {
my ($query) = #_; # take a prompt string as argument
local $| = 1; # activate autoflush to immediately show the prompt
print $query;
chomp(my $answer = <STDIN>); return $answer;
}
sub prompt_num {
NSTART:
my ($querynum) = #_;
print $querynum;
chomp(my $pnum = <STDIN>);
if ($pnum eq $pnum+0) { return $pnum; }
else { print "Error: That is not a number. Try again.\n"; goto NSTART; }
}
sub prompt_yn {
my ($queryyn) = #_;
my $answer = prompt("$queryyn (y/N): ");
return lc($answer) eq 'y';
}
I'd like to also point out that I'm new to perl.
OK, wow. Stop for a moment, step back and put the code down. Think about what you're trying to accomplish here.
There's a bunch of things you're doing in your code that's really going to benefit from taking a step back, and understanding what's going on, before proceeding.
First off:
my $arg = shift(#ARGV);
my $subname = $arg;
if (!defined($arg)){
cmd_go();
}
What is this intended to do? You only use $arg 3 times here, and one of those is to copy it to $subname.
This could be quite simplified by:
my $subname = shift;
cmd_go() unless defined $subname;
Now this:
my $sub = main->can("cmd_$subname") || main->can("dev_$subname") || main->can("hid_$subname");
Where did that come from? Because I'm pretty sure that - as a beginner to perl - you didn't write that yourself, not least because you don't have any subroutines prefixed with dev_ or hid. And this sort of redirect is serious overkill for a program that basically does just one thing.
(And normally, you'd use flags like getopt rather than a command that you leave blank in a default state).
You are also massively overusing arrays - which suggests you're not really sure the difference between #game and $game.
E.g. this:
my #game = prompt("What game are we scoring?\n");
prompt does this though:
chomp(my $answer = <STDIN>); return $answer;
It returns a scalar (a single line) and you're putting it into an array for - as far as I can tell - no particular reason.
Likewise this:
my #p1score = prompt_num("score for #p1name?\n");
my #p2score = prompt_num("score for #p2name?\n");
my #p3score = prompt_num("score for #p3name?\n");
First off - you're using a bunch of single element arrays. But then you're numbering them. When ... actually, the whole point of arrays is to have numbered values.
So how about instead:
print "Num players?:\n";
chomp ( my $num = <STDIN> );
my #players;
my %scores;
for ( 1..$num ) {
print "Player name\n";
chomp ( my $name = <STDIN> );
push ( #players, $name );
}
foreach my $person ( #players ) {
print "Score for $person:\n";
chomp ( my $score = <STDIN> );
while ( $score =~ /\D/ ) {
print "Invalid - please enter numeric value\n";
chomp ( $score = <STDIN> );
}
$scores{$person} = $score;
}
foreach my $person ( #players ) {
print "$person => $score{$person}\n";
}
There are a bunch of other things that you're doing that is more complicated than it needs to be.
What I would suggest you do:
go re-read the perl basics. perldata in particular.
have a look at getopt which is a good (and standard) way to take program 'flag' style input. (e.g. showing version, if that's what you really want.
it looks a lot like you've cargo-culted the code here. I would suggest you re-write from the ground up, and when you hit a problem - ask about it on Stack Overflow, if you can't figure it out from the perl docs.
Try this. Hope this is what you wanted.
#!/usr/bin/env perl
use strict;
my $version = "1.0";
my $arg = shift(#ARGV);
my $subname = $arg;
if (!defined($arg)){
cmd_go();
}
$subname =~ s/-/_/g;
my $sub = main->can("cmd_$subname") || main->can("dev_$subname") || main->can("hid_$subname");
if (!defined($sub))
{
print STDERR "Invalid command given.\nUse \e[1;32m./skore help\e[0m for a list of commands.\n";
exit 1;
}
else
{
$sub->(#ARGV);
exit 0;
}
# Main command
sub cmd_go()
{
print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
print "••••••••••••••••••••\n";
print "• Welcome to \e[1;32mskore\e[0m •\n";
print "••••••••••••••••••••\n\n";
my #game = prompt("What game are we scoring?\n");
print "••• Game name locked: #game\n\n";
my $players= prompt("Enter total number of players:\n");
my #players_list;
for(my $i=0;$i<$players;$i++){
push(#players_list , prompt("Enter Player ".($i+1)." name\n"));
}
print "\n";
print "••• Player names locked: ";
for(my $i=0;$i<$players;$i++){
print $players_list[$i]."\t";
}
print "\n\n";
my #players_score;
for(my $i=0;$i<$players;$i++){
push(#players_score, prompt("score for $players_list[$i]?\n"));
}
print "\n";
print "••• Game: #game\n";
for(my $i=0;$i<$players;$i++){
print "$players_list[$i]\n";
print "••••• \e[1;32m$players_score[$i]\e[0m\n";
}
exit 1;
}
sub cmd_help()
{
print "To get right into using skore, simply type ./skore\n";
print "For details about skore, such as version, use ./skore pkg\n";
}
sub cmd_pkg()
{
print "skore version: $version\n";
print "Detected OS: ";
exec "uname -r";
}
sub prompt {
my ($query) = #_; # take a prompt string as argument
local $| = 1; # activate autoflush to immediately show the prompt
print $query;
chomp(my $answer = <STDIN>); return $answer;
}
sub prompt_num {
NSTART:
my ($querynum) = #_;
print $querynum;
chomp(my $pnum = <STDIN>);
if ($pnum eq $pnum+0) { return $pnum; }
else { print "Error: That is not a number. Try again.\n"; goto NSTART; }
}
sub prompt_yn {
my ($queryyn) = #_;
my $answer = prompt("$queryyn (y/N): ");
return lc($answer) eq 'y';
}
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";
}
}
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 am attempting to write a code that will encrypt letters with a basic cyclic shift cipher while leaving any character that is not a letter alone. I am trying to do this through the use of a sub that finds the new value for each of the letters. When I run the code now,it formats the result so there is a single space between every encrypted letter instead of keeping the original formatting. I also cannot get the result to be only in lowercase letters.
sub encrypter {
my $letter = shift #_;
if ($letter =~ m/^[a-zA-Z]/) {
$letter =~ y/N-ZA-Mn-za-m/A-Za-z/;
return $letter;
}
else {
return lc($letter);
}
}
print "Input string to be encrypted: ";
my $input = <STDIN>;
chomp $input;
print "$input # USER INPUT\n";
my #inputArray = split (//, $input);
my $i = 0;
my #encryptedArray;
for ($i = 0; $i <= $#inputArray; $i++) {
$encryptedArray[$i] = encrypter($inputArray[$i]);
}
print "#encryptedArray # OUTPUT\n";
You might try changing this line:
if ($letter = m/[^a-zA-Z]/ ) {
To something more like this:
if ($letter =~ m/^[a-zA-Z]/) {
In the original line you are doing an assignment to the variable $letter, and the ^ will need to be before the [a-zA-Z] for the comparison.
You're attempting to do a rot13 translation on your characters. This can be done a little easier using tr:
use strict;
use warnings;
sub rot13 {
my $string = shift;
$string =~ tr/a-zA-Z/n-zA-Za-m/;
return $string;
}
print "Input string to be encrypted: ";
chomp(my $input = <STDIN>);
print "$input # USER INPUT\n";
print "Cycle of 4:\n";
for (1..4) {
$input = rot13($input);
print " $input\n";
}
Outputs
Input string to be encrypted: asdf
asdf # USER INPUT
Cycle of 4:
nFqs
ASDF
NfQS
asdf
Here is a some kind of more general implementation of it, it is easier to adapt it to something like, for example, using different rotation places for different letter:
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(switch say);
sub rotateBy {
my ($letter, $rotate_places) = #_;
$rotate_places = $rotate_places ? $rotate_places : 13;
my $width = (ord 'z') - (ord 'a') + 1;
sub rotate {
my ($let, $base, $places, $width) = #_;
my $i = (ord $let) - (ord $base);
return chr((ord $base) + ($i + $places) % $width);
}
given ($letter) {
when (m/[a-z]/) {
return rotate ($letter, 'a', $rotate_places, $width);
}
when (m/A-Z/) {
return rotate ($letter, 'A', $rotate_places, $width);
}
default {
return $letter;
}
}
}
while (<>) {
chomp;
print "PLAINTEXT : $_\n";
print "CIPHERTEXT: ";
foreach my $let (split //) {
print rotateBy($let);
}
print "\n";
}
By the way, the above code looks too verbose to me, maybe there is a better way to do it.