Just started to learn Perl and namely, learn program flow - main notable differences between evaluating strings and number and using the appropriate operators. Simple script, I have here is driving me crazy as it's a super simple, if else statement that should on "mike" being entered run and doesn't work. It outputs the else statement instead. Please help
#!C:\strawberry\perl\bin\perl.exe
use strict;
#use warnings;
#use diagnostics;
print("What is your name please?");
$userName = <STDIN>;
if($userName eq "mike"){
print("correct answer");
}
else{
print("Wrong answer");
}
Try adding a call to chomp after you get your value from STDIN:
$userName = <STDIN>;
chomp($userName);
Since the value read in from STDIN will have a newline character on the end. The chomp() built-in will remove a newline from the end of a string.
As I read your question I thought you were about to have a problem with strings versus numeric values in an equals. Consider the following case:
#!/usr/bin/env perl
use strict;
use warnings;
print("What is the meaning of life, the universe and everything? ");
chomp(my $response = <STDIN>);
if ( $response == 42) {
#if ( 42 ~~ $response ) {
print "correct answer\n";
} else {
print "Wrong answer\n" ;
}
Try the two different if statements. Answer something nice like family and see what happens. The ~~ is the smart match operator which has helped some of this problem in Perl. Read more about it here (under "smart matching in detail"). Note also the inline use of the chomp operator.
Related
I am attempting to create a Perl script that filters data presented on STDIN, changing all occurrences of
one string to another and outputting all input lines, changed and unchanged to STDOUT. FROMSTRING and TOSTRING can be PERL-compatible regular expressions. I am unable to get matching output.
Here is an example of what I am trying to achieve.
echo "Today is Saturday" | f.pl 'a' '#'
Output Tod#y is S#turd#y.
echo io | filter.pl '([aeiou])([aeiou])' '$2$1'
Output oi.
#!/usr/bin/perl
use strict;
use warnings;
if (#ARGV != 2){
print STDERR "Usage: ./filter.pl FROMSTRING TOSTRING\n"
}
exit 1;
my $FROM = $ARGV[0];
my $TO = $ARGV[1];
my $inLine = "";
while (<STDIN>){
$inLine = $_;
$inLine =~ s/$FROM/$TO/;
print $inLine
}
exit 0;
First off, the replacement part of a s/.../.../ operation is not a regex; it works like a double-quoted string.
There are a couple of issues with your code.
Your exit 1; statement appears in the middle of the main code, not in the error block. You probably want:
if (#ARGV != 2) {
print STDERR "Usage: ./filter.pl FROMSTRING TOSTRING\n";
exit 1;
}
You're missing a g flag if you want multiple substitutions to happen in the same line:
$inLine =~ s/$FROM/$TO/g;
There's no need to predeclare $inLine; it's only used in one block.
There's also no need to read a line into $_ just to copy it into $inLine.
It's common to use $names_like_this for variables and functions, not $namesLikeThis.
You can use $0 instead of hardcoding the program name in the error message.
exit 0; is redundant at the end.
The following is closer to how I'd write it:
#!/usr/bin/perl
use strict;
use warnings;
if (#ARGV != 2) {
die "Usage: $0 FROMSTRING TOSTRING\n";
}
my ($from, $to) = #ARGV;
while (my $line = readline STDIN) {
$line =~ s/$from/$to/g;
print $line;
}
That said, none of this addresses your second example with '$2$1' as the replacement. The above code won't do what you want because $to is a plain string. Perl won't scan it to look for things like $1 and replace them.
When you write "foo $bar baz" in your code, it means the same thing as 'foo ' . $bar . ' baz', but this only applies to code, i.e. stuff that literally appears in your source code. The contents of $bar aren't re-scanned at runtime to expand e.g. \n or $quux. This also applies to $1 and friends, which are just normal variables.
So how do you get '$2$1' to work?
One way is to mess around with eval, but I don't like it because, well, it's eval: If you're not very careful, it would allow someone to execute arbitrary code by passing the right replacement "string".
Doing it without eval is possible and even easy with e.g. Data::Munge::replace:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Munge qw(replace);
if (#ARGV != 2) {
die "Usage: $0 FROMSTRING TOSTRING\n";
}
my ($from, $to) = #ARGV;
while (my $line = readline STDIN) {
print replace($line, $from, $to, 'g');
}
replace works like JavaScript's String#replace in that it expands special $ sequences.
Doing it by hand is also possible but slightly annoying because you basically have to treat $to as a template and expand all $ sequences by hand (e.g. by using another regex substitution):
# untested
$line =~ s{$from}{
my #start = #-;
my #stop = #+;
(my $r = $to) =~ s{\$([0-9]+|\$)}{
$1 eq '$'
? '$'
: substr($from, $start[$1], $stop[$1] - $start[$1])
}eg;
$r
}eg;
(This does not implement braced groups such as ${1}, ${2}, etc. Those are left as an exercise for the reader.)
This code is sufficiently annoying to write (and look at) that I much prefer using a module like Data::Munge for this sort of thing.
three errors found:
; after error message
exit 1;
$inLine =~ s/$FROM/$TO/g;
like:
#!/usr/bin/perl
use strict;
use warnings;
if (#ARGV != 2){
print STDERR "Usage: ./filter.pl FROMSTRING TOSTRING\n";
exit 1;
}
my $FROM = $ARGV[0];
my $TO = $ARGV[1];
my $inLine = "";
while (<STDIN>){
$inLine = $_;
$inLine =~ s/$FROM/$TO/g;
print $inLine
}
exit 0;
I want to check that the input from the user is an integer number. I tried the following, but it doesn't work:
try {
print "Enter int";
$num=int(<>);
print "okej";
}
catch (ValueError $e{
print"not int";
}
You really do not want to punish users for leading/trailing spaces (as too many web sites these days seem to be doing), but also avoid leading zeros. Also, make sure the output is flushed before asking for input:
#!/usr/bin/env perl
use strict;
use warnings;
my $input;
until (defined $input) {
local $| = 1;
print 'Enter an integer: ';
($input) = (<STDIN> =~ /\A \s* (-? [1-9] [0-9]* ) \s* \z/x);
}
print "$input\n";
The int function does not check if something is an integer. Instead, it converts its argument to an integer. So, int(1) is 1, int(1.11) is also 1, and int('a') is 0 — with a warning if you enabled warnings.
See also:
"How do I determine whether a scalar is a number/whole/integer/float?" in perlfaq4. You should read the excellent documentation that comes with Perl.
perldoc -v '$|'
Check to see if input has only digits and nothing else...
use warnings;
use strict;
print "Enter integer: ";
my $input = <>;
chomp $input;
print "is int\n" if $input =~ /^[0-9]+$/;
I am a beginner to perl and have just been messing around trying to create little scripts. I'm not sure what is wrong here but it just falls through to the else every time as if nothing I input satisfies the if or elsif conditions. Is it because eq is the wrong operator? Or is there something else wrong in my code? Thanks!
#!/usr/bin/perl
use strict;
use warnings;
print "what is your name?\n";
my $name = readline STDIN;
print "Hello $name How are you today?\n";
my $feeling = readline STDIN;
if ($feeling eq "happy") {
print "that's good!\n";
}
elsif ($feeling eq "good") {
print "okay!\n";
}
else {
print "Interesting\n";
}
Use chomp($feeling);
#!/usr/bin/perl
use strict;
use warnings;
print "what is your name?\n";
my $name = readline STDIN;
chomp($name);
print "Hello $name How are you today?\n";
my $feeling = readline STDIN;
chomp($feeling);
if ($feeling eq "happy") {
print "that's good!\n";
}
elsif ($feeling eq "good") {
print "okay!\n";
}
else {
print "Interesting\n";
}
readline STDIN captures every character typed along with last enter hit as \n, say if you type "happy" and hit enter for $feeling then its accepted as "happy\n" notice \n is because enter hit to remove last \n newline character use chomp removes any trailing string
chomp is used to "chomp off" the input record separator, which by default is a newline character.
#!/usr/bin/perl
use strict;
use warnings;
use 5.012; # to use things like 'say' and 'given'
say "what is your name?"; # 'say' is like 'print', but means you don't have to use '\n'
my $name = <STDIN>; # good to include angled brackets <>
chomp($name); # remove the newline when entering the number
say qq{Hello $name, how are you today?}; # qq{} acts like double-quotes ("")
my $feeling = <STDIN>;
chomp $feeling; # notice parenthese aren't always needed
# you could also do chomp(my $feeling=<STDIN>);
given (lc $feeling){ # 'given' is Perl's version of a Switch and lc makes input lowercase
when('happy') { say q{That's good.} } # q{} acts like single-quotes ('')
when('good') { say q{Okay!} }
default { say q{Interesting} } # your else-case
}
As the warnings suggest, given is experimental until smartmatch is figured out. It is perfectly acceptable to use the if-elsif-else structure, if you choose.
I'm having trouble making yes/no questions with Perl, and I just couldn't figure it out. I'm kinda a noob at this.
#! usr/bin/perl
print "Hello there!\n";
print "What is your favorite game?\n";
$name = <STDIN>;
chomp $name;
print "That's awesome! $name is my favorite game too!\n";
print "Do you think this is a fun script (Y/n) \n";
$status = <STDIN>;
if [ $status = "y" ]: then
print "YAY! I knew you would like it!\n";
if [ $status = "n" ]: then
print "You suck, not me!\n";
What am I doing wrong?
if [ is a shell syntax. In Perl, you should use
if (...) {
Also, = is the assignment operator. For string equality, use eq:
if ($status eq 'y') {
print "YAY\n";
Before comparing, you should chomp $status the same way you're already chomping $name.
Also, note that Y and y are not equal.
Also, your first ("shebang") line misses the starting slash:
#! /usr/bin/perl
if [ $status = "y" ]: then
That's Bourne (or bash) shell syntax. The equivalent Perl code is:
if ($status eq "y") {
# ...
}
eq is equality comparison for strings; == compares numbers.
(The other thing you're doing wrong is not including the error message in your question.)
For example:
$status = <STDIN>;
chomp $status;
if ($status eq "y") {
print "YAY! I knew you would like it!\n";
}
There are some other things you can do to improve your Perl code. For example, you should always have:
use strict;
use warnings;
near the top of the source file (which will require declaring your variables, probably with my). I suggest getting this program working first before worrying about that, but it's definitely something you'll want to do in the long term.
First, always, always put use strict; and use warnings; at the top of your programs. This will catch all sorts of errors such as using = in if statements. = sets a variable's value. == tests numeric equality and eq tests string equality.
Here's your program rewritten. The first line with #! searches your PATH for an executable Perl. This way, you don't have to worry whether Perl is in /usr/bin/perl or /bin/perl or /usr/local/bin/perl.
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say); # Allows the use of the "say" command
say "Hello there!";
print "What is your favorite game? ";
my $name = <STDIN>;
chomp $name;
say "That's awesome! $name is my favorite game too!";
print "Do you think this is a fun script (Y/n) \n";
my $status = <STDIN>;
chomp $status;
if ( $status eq "y" ) {
say "Yay! I knew you would like it!";
}
elsif ( $status eq "n" ) {
say "You suck, not me!";
}
A better way may be to check whether the input started with a y or not:
if ( $status =~ /^y/i ) { # Did it start with a 'y' or 'Y'?
say "Yay! I knew you would like it!";
else {
say "You suck, not me!";
}
Note the use of my to declare variables. This is something use strict; requires and will catch a lot of programming mistakes. Note that say is like print, but I don't have to keep putting \n on the end.
For some reason, my if statements aren't working the way I want them to.
use strict;
use warnings;
my $syl;
my $name = "Chris";
print "Enter my name\n";
$syl = <>;
if ($syl eq $name)
{
print "You entered my name!\n";
}
else
{
print "That's not my name!\n";
}
It looks like it should work from all of the tutorials I've read, but when I type in "Chris" whether capitalized, lowercase, with or without quotation marks, it always evaluates to false. Use Strict and Use Warnings don't tell me I'm doing anything wrong so what, if anything, can I do?
You need to use chomp. That strips the newline from the end of the input string that got put there when the user typed 'enter.'
$syl = <>;
chomp $syl;
#.... etc...