Wrong check with Strings - perl

I'm new to Perl and can't understand, why this check has the output false:
// $answer would be a Global Variable
my $answer;
// the rest is in a sub scope
print "Do you want to proceed? (Y/N)";
$answer = uc <STDIN>;
if($answer eq "Y"){
print "success";
} else {
print "why";
}

Look at what the value of $answer actually is:
print "---$answer---";
It outputs
---Y
---
So it isn't equal to "Y", it is equal to "Y\n".
Use chomp on the string.

Related

Issue with goto statement along with if else condition

I am trying to create a simple perl assignment for equality check and goto label concept.
User enters numbers , equality check happens, user is asked if they want to check more , if yes then it repeats, else it exits. Using "goto " for this
Issue- y/n checks for repeating,y is for repeating Label. even if I enter "n" it keeps going to the label Loop .
Why is the "if" condition containing "goto" not getting honored?
Code below
#Checking Equality
Loop: print "\Checking Equality\n";
print "Enter number for variable a\n";
$a = <stdin>;
print "Enter number for variable b\n";
$b = <stdin>;
if ( $a == $b ) {
print 'a and b are equal';
print "\n\n";
}
else {
print 'a and b are not equal';
}
print "\n\n";
print "do you want to check more? Enter y/n\n";
$c = <stdin>;
if ( $c == "y" ) {
goto Loop;
}
elsif ( $c == "n" ) {
print "Exiting\n";
}
Output-
Checking Equality
Enter number for variable a
3
Enter number for variable b
4
a and b are not equal
do you want to check more? Enter y/n
n
Checking Equality #### despite of entering n goto Loop is getting executed
Enter number for variable a
Just use chomp function to remove newline(s), and use eq comparison for string.
use strict;
use warnings;
Loop: print "\nChecking Equality\n";
print "Enter number for variable a\n";
my $a = <stdin>;
print "Enter number for variable b\n";
my $b = <stdin>;
if ( $a == $b ) {
print 'a and b are equal';
print "\n\n";
}
else {
print 'a and b are not equal';
}
print "\n\n";
print "do you want to check more? Enter y/n\n";
chomp(my $c = <stdin>);
if ( $c eq "y" ) {
goto Loop;
}
else {
print "Exiting\n";
}
You have chosen not best approach to use a label for goto.
Instead loop would be more appropriate to perform user input. User stays in the loop until he/she will not specify that he/she ready to leave.
User's input also should be stripped off newline symbol \n before it can be used for comparison.
As user suppose to provide input several time then it would be beneficial to use small subroutine to print 'input prompt', collect input, strip newline symbol and return input value. By doing so the program becomes shorter and easier to read.
String comparison operation performed with eq, number comparison performed with ==.
use strict;
use warnings;
use feature 'say';
my $answer = 'y';
while( $answer eq 'y' ) {
my $num_1 = get_input('Enter variable num_1: ');
my $num_2 = get_input('Enter variable num_2: ');
my $compare = $num_1 == $num_2 ? 'EQUIAL' : 'NOT EQUIAL';
say "\nNumbers are $compare\n";
$answer = get_input('Would you like to continue? (y/n) ');
$answer = lc $answer;
say '-' x 35;
}
sub get_input {
my $msg = shift;
my $input;
print $msg;
$input = <>;
chomp $input;
return $input;
}

String matching in perl (if statement in for loop) [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have following code
#!C:\Perl64\bin -w
#use strict; use warnings;
init_words();
print "What is your name Mr. \n";
$name = <STDIN>;
chomp ($name);
if ($name =~ /^randal\b/i){
print "Hello, Randal, How are you doing \n";
} else {
print "Hello, $name!\n";
print "Tell the secret word\n";
$guess = <STDIN>;
chomp ($guess);
while (!good_word ($name,$guess)) {
print "Wrong, please try again\n";
$guess = <STDIN>;
chomp ($guess);
}
}
sub init_words {
open (WORDSLIST, "wordslist.txt") || die "can't open wordslist: $!";
$k = 1;
$a = 0;
$b = 0;
while (defined ($name = <WORDSLIST>)) {
if ($k % 2 == 0) {
chomp ($name);
$words1[$a] = $name;
++$k;
++$a;
} else {
chomp ($name);
$words2[$b] = $name;
++$k;
++$b;
}
}
close (WORDSLIST) || die "couldn't close wordlist: $!";
}
sub good_word {
my ($somename, $someguess) = #_;
$somename =~ s/\W.*//;
$somename =~ tr/A-Z/a-z/;
if ($somename eq "randal") {
return 1;
} else {
#$n = 0;
#words1 has secret words.
#words2 has names.
$t = scalar #words1;
$u = scalar #words2;
print "the words1 array is #words1 \n";
print "the words2 array is #words2 \n";
for ($d = 0; $d < $u; $d++) {
#print "currently name in array is #words2[$d]\n";
print "The value of somename is $somename \n";
$delta = $words2[$d];
print "The value of delta is $delta";
#use strict; use warnings;
if ($delta eq '$somename') {
print "test";
return 1;
}
}
#print "The final value of d is $d";
#print " The final value of array is #words1[$d]";
#if ("groucho" eq $someguess) {
#return 1;}
#else{
#while ($n < $t){
#if (#words1[$n] eq $someguess) {
#return 1;}
#else { ++$n};
}
The main goal of the code is to have wordslist defined. The code should split the wordslist into two sublists i.e. #words1 and #words2. User is asked for a name and then secret guess. The code should check for the name in the #words2 and if match is found program exit (with printing test).
For some reason, it is not working as expected. I tried doing some basic debugging and everything looks ok but in the function good_word, the if statement under for loop is never returned true although i can see in my debugging that both $somename and $delta are same.
Any suggestions??
Change
if ($delta eq '$somename'){
to
if ($delta eq $somename){
Perl strings with double quotes (") will interpolate variables like $somename but strings with single quotes (') will not do that.
Reference to documentation about that: http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators

Perl program to calculate the sum of the numbers that the user enters

My script needs to get a series of numbers input by the user and find the average of them. I would like to use the line 'end-of-file' to show that the user is done inputting code. Any help would be appreciated. Below is what I have so far. I think I am really close, but I am missing something.
Code:
#! /usr/bin/perl
use 5.010;
print "Enter the scores and type end-of-file when done";
chomp(#scores = <STDIN>);
foreach (#scores) {
push_average(total(#scores));
}
sub total {
my $sum;
foreach (#_) {
$sum += $_;
}
sum;
}
sub average {
if (#_ == 0) {return}
my $count = #_;
my $sum = total(#_);
$sum/$count;
}
sub push_average {
my $average = average(#_);
my #list;
push #list, $average;
return #list;
}
You are quite close. Adding use strict; use warnings at the top of every Perl script will alert you of errors that might go unnoticed otherwise.
A few hints:
You forgot the sigil of $sum in the last statement of total. Currently, you return a string "sum" (without strict vars), or possibly call a sub called sum.
You don't need the foreach in the main part, rather do
my #averages = push_average(#scores);
The total is already calculated inside push_average
You probably want to print out the resulting average:
my $avg = $averages[0];
say "The average of these numbers is $avg";
The push_average is silly; you return a new array of one element. You could return that one element just as well.
Suggested script:
use strict; use warnings; use 5.010;
use List::Util qw/sum/; # very useful module
# say is like print, but appends a newline. Available with 5.10+
say "Please enter your numbers, finish with Ctrl+D";
my #nums = <STDIN>;
chomp #nums;
# The // is the defined-or operator
# interpolating undef into a string causes a warning.
# Instead, we give an expressive message:
my $avg = average(#nums) // "undefined";
say "The average was $avg";
sub average { #_ ? sum(#_) / #_ : undef } # return undef value if called without args
reads up to the newline. You've got a few choices here. You can ask the user to input the numbers separated by spaces and then split it into your #choices array. Or you can keep asking them to enter a number or just hit enter to finish.
Answer 1)
print "Enter scores separated by a space and press enter when done";
chomp($input = <STDIN>);
#choices = split(' ', $input);
Answer 2)
#chomp = ();
do {
print "Enter a score and then press enter. If done, just press enter.";
chomp($temp = <STDIN>);
if($trim ne '') {
push(#choices, $temp);
}
} until ($temp eq '');

perl equal strings returns 0 even if they are equal

Perl is continuing to surprise me. I have a code which takes an input from the command line and checks if it is in a file. I have a file like this:
ls
date
pwd
touch
rm
First i read this file as
open(MYDATA,"filename") or die "Can not open file\n";
#commandlist = <MYDATA>;
chomp #commandlist;
close MYDATA;
the argument is in $commandname variable. To check if it is correct i printed to screen.
print $commandname."\n";
it works well. then i write the code.
$count = #commandlist;
for($i=0;$i < $count;$i++)
{
print $commandname;
print $commandlist[$i];
print "\n";
if($commandname eq $commandlist[$i])
{
print "equal\n";
}
}
and it does not print 'equal'. but it should do becaues $commandname variable has the value 'ls' which is in the file. i also print the value of $commandname and $commandlist[$i] to see if "visibly" they are equal and i get the output:
ls
lsls
lsdate
lspwd
lstouch
lsrm
here i see that they got the same value but why never eq operator evaluates to zero.
Additionally to get this task done, I have tried various methods all of which come to be useless like making a hash from the array and using exists.
I am struggling for this seemingly easy problem for a day but i just dont get it.
Thanks in advance
EDIT:
when i change the above loop as below
$count = #commandlist;
for($i=0;$i < $count;$i++)
{
print $commandlist[$i];
print $commandname;
print "\n";
if($commandname eq $commandlist[$i])
{
print "equal\n";
}
}
I got an output like.
ls
ls
lste
lsd
lsuch
ls
it seems like for some reason it overwrites some characters.
EDIT:
my whole script is like:
#reading file code, i posted above
while(<>)
chomp($_);
$commandname = $_;
if($commandname eq "start"){
##something here
} elsif ($commandname eq "machines"){
##something here
} else {
$count = #commandlist;
for($i=0;$i < $count;$i++)
{
print $commandlist[$i];
print $commandname;
print "\n";
if($commandname eq $commandlist[$i])
{
print "equal\n";
}
}
}
A bit change in the code would result in what you are looking for, "chomp" the string from array before you put it for comparison. Here it is
chomp $commandlist[$i];
if($commandname eq $commandlist[$i])
{
print "equal\n";
}
EDIT: as per perldoc chomp when you are chomping a list you should parenthesis. So, in your case ... instead simply saying
chomp #commandlist
make it like
chomp(#commandlist)
FINAL EDIT: I tried this and worked fine. Give it a try
$commandname = $ARGV[0];
open(MYDATA,"chk.txt") or die "Can not open file\n";
#commandlist = <MYDATA>;
chomp(#commandlist);
close MYDATA;
print $commandname."\n";
$count = #commandlist;
print $commandname;
for($i=0;$i < $count;$i++)
{
print $commandlist[$i];
print "\n";
if($commandname eq $commandlist[$i])
{
print "equal\n";
}
}
The overwritting indicates the presence of a CR. The lines end with CR LF, but you only remove the LF with chomp. Change
while (<>) {
chomp($_)
to
while (<>) {
s/\s+\z//;
You might consider restructuring your code as:
my $path='filename';
my $match='ls';
part 1 - read the file
open(my $fh, '<', $path) or die "failed to open $path: $!";
my #commandlist=<$fh>;
chomp #commandlist;
# or you can combine these lines as:
# chomp(my #commandlist=<$fh>);
# because chomp operates on the array itself rather than making a copy.
close($fh);
or
use File::Slurp qw/ read_file /;
# see http://search.cpan.org/dist/File-Slurp/lib/File/Slurp.pm
my #commandlist=read_file($path); # result is pre-chomped!
part 2 - check for a match
foreach my $command (#commandlist) {
print "$match equals $command\n" if $match eq $command;
}
One important consideration is that each line in your file must contain only the command name and cannot begin or end with any spaces or tabs. To compensate for possible leading or trailing whitespace, try:
foreach my $command (#commandlist) {
$command=~s/^\s+|\s+$//g; # strip leading or trailing whitespace
print "$match equals $command\n" if $match eq $command;
}
And finally, always start your Perl script with a Perl developer's bestest friends:
use strict;
use warnings;
which will catch most (if not all) errors caused by sloppy programming practice. (We all suffer from this!)

Why doesn't my string equality test for a single character work?

How does one compare single character strings in Perl? Right now, I'm tryin to use "eq":
print "Word: " . $_[0] . "\n";
print "N for noun, V for verb, and any other key if the word falls into neither category.\n";
$category = <STDIN>;
print "category is...." . $category . "\n";
if ($category eq "N")
{
print "N\n";
push (#nouns, $_[0]);
}
elsif($category eq "V")
{
print "V\n";
push (#verbs, $_[0]);
}
else
{
print "Else\n";
push(#wordsInBetween, $_[0]);
}
But it isn't working. Regardless of the input, the else block is always executed.
How are you accepting the value of $category? If it is done like my $category = <STDIN>, you will have to chomp the newline at the end by:
chomp( my $category = <STDIN> );
eq is correct. Presumably $category is neither "N" nor "V".
Maybe there's unexpected whitespace in $category?
***#S04:~$ perl -we '$foo = "f"; print "Success\n" if ($foo ne "e")'
Success
***#S04:~$ perl -we '$foo = "f"; print "Success\n" if ($foo eq "e")'
***#S04:~$
Have you tried checking what $category actually is? Sometimes these things can slip by even the best of us... Perhaps it is lowercase, or something different altogether.
When I get unexpected errors, I tend to use a print with delimiters around what I want to print, so I know where it actually starts and ends (as opposed to what my mind might interpret).
print "|>${category}<|";
Something else of note, is Data::Dumper:
use Data::Dumper;
print Dumper(\$category);
Comparing with eq works just fine. Maybe you should output the value of $category in your else-block to see what it really is? Enclose the output in quotes so you can see if there is any surrounding whitespace.
Also, if you want the comparisons to be case-insensitive, try:
if (uc($category) eq 'N') {
Here is how I would write it if I could use Perl 5.10.
#! perl
use strict;
use warnings;
use 5.010;
our( #nouns, #verbs, #wordsInBetween );
sub user_input{
my( $word ) = #_;
say "Word: $word";
say "N for noun, V for verb, and any other key if the word falls into neither category.";
$category = <STDIN>;
chomp $category;
say "category is.... $category";
given( lc $category ){
when("n"){
say 'N';
push( #nouns, $word );
}
when("v"){
say 'V';
push( #verbs, $word );
}
default{
say 'Else';
push( #wordsInBetween, $word );
}
}
}