I am trying to write a palindrome checker in Perl. It's supposed to return "true"
if the input is the same forwards and backwards.
Example:
./determine kayak
True
./determine "Do geese see God?"
True
./determine "Do ducks see God?"
False
My code:
#!/usr/bin/perl -w
$name = $ARGV[0];
$name = lc $name;
$name =~ s/[^a-z]//g;
@all = split //,$name;
$half = $#all/2;
foreach $i (0..$half){
my $count = 0;
if($all[$i] eq $all[-($i+1)]){
#print"$all[$i]\n";
#print"$all[-($i+1)]\n";
print "true\n";
last;
}else{
print "flase\n";
}
}
It can't determine true or false after read all.
For example: when read: "Do ducks see God?"
, the first two letter is same, so it will print true, but this should be false.
Your code only checks the first letter and then stops the loop if they are the same. You've correctly identified that problem. It's because of the last
.
foreach $i (0..$half){
my $count = 0;
if($all[$i] eq $all[-($i+1)]){
print "true\n";
last; # <-- here
}else{
print "flase\n";
}
}
This will make Perl exit the loop. What you want to do instead is keep checking every letter. Once you've reached the middle, your result is true because the string is a palindrome . But as soon as you see a mismatch, you have to fail and exit.
You do that by keeping a status in a variable, and checking afterwards. I've added strict
and warnings
and made the code a bit shorter.
my $name = lc 'Do ducks see God?';
$name =~ s/[^a-z]//g;
my @all = split //, $name;
my $half = $#all / 2;
my $is_palindrome = 1;
foreach my $i ( 0 .. $half ) {
my $count = 0;
if ( $all[$i] ne $all[ -( $i + 1 ) ] ) {
$is_palindrome = 0;
last;
}
}
if ($is_palindrome) {
print "true\n";
} else {
print "false\n";
}
It's easier to use a ne
check , because having an empty block after the if
like this is confusing.
if ( 1 == 0 ) {
} else {
# do stuff
}
It's easier to turn the condition around and get rid of the block, or use unless
, which is the same as if not in Perl.
if ( 1 != 0 ) {
# do stuff
}
unless ( 1 == 0 ) {
# do stuff
}
Note that there is a way shorter implementation: You can compare the string with its reverse
. The reverse
built-in , when called in scalar context, turns the string around.
my $name = lc '12321';
$name =~ s/[^a-z]//g;
if ($name eq reverse $name) {
print "true\n";
} else {
print "false\n";
}
Currently, you print "true" or "false" for every iteration of your array of characters. You really want to check each letter and only print the result at the end.
my $is_palindrome = 1;
foreach $i (0..$half){
if ($all[$i] ne $all[-($i+1)]){
$is_palindrome = 0;
last;
}
}
say $is_palindrome ? 'true' : 'false';
But, personally, I think it's easier just to check your $name
variable is the same as its reverse.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my $name = $ARGV[0];
$name = lc $name;
$name =~ s/[^a-z]//g;
say $name eq reverse($name) ? 'true' : 'false';
Note: Please use use warnings
instead of -w
and also use strict
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.