I'm trying to write a short script in Perl to go through a an array of strings provided by the user, check in a hash table to see if there are vowels in the strings, then return the strings minus the vowels. I know this would be easier to accomplish using regex, but the parameters for the problem state that a hash table, exists()
, and split()
must be used. This is the script I have so far:
my @vowels = qw(a e i o u A E I O U);
my %vowel;
foreach $v (@vowels) {
$vowel{$v} = undef;
}
foreach $word (@ARGV) {
my @letter_array = split(undef,$word);
}
foreach $letter (@letter_array) {
print($letter) if !exists($vowel{$letter})
}
print "\n"
Input: hello
Expected output: hll
Actual output: nothing
There are no error messages, so I know it's not a syntax error. Any ideas what I'm messing up? I'm much more comfortable with Python and this is one of my first attempts at Perl.
CodePudding user response:
You should use strict
not to mess visibility of your variables.
If you use perl version 5.10
of higher it would be used automatically.
So your list @letter_array
exists only in foreach my $word (@ARGV)
loop. That's why it's empty in the end.
If you want to fix that you'll get the following code:
#!/usr/bin/env perl
use strict;
my @vowels = qw( a e i o u y A E I O U Y );
my %vowel;
foreach my $v (@vowels) {
$vowel{$v} = undef;
}
my @letter_array;
foreach my $word (@ARGV) {
@letter_array = split(undef, $word);
}
foreach my $letter (@letter_array) {
print($letter) if !exists($vowel{$letter})
}
print "\n"
But this code is still not practical.
- If you would get more that 1 word in the input, you'll show only the last one, because the @ letter_array overwrites each time.
- You can use
map
to get the hash of vowels much easier without using extra variables. - You can use less loops if you would handle each word right after reading it.
- You can also use
unless
if you want to checkif not
to make it prettier and more perl-style. - You can use
for
instead offoreach
because it's the same but shorter :)
So you can get an optimised solution.
#!/usr/bin/env perl
use 5.012;
my %vowels = map { $_ => undef } qw( a e i o u y A E I O U Y );
for my $word (@ARGV) {
my @letters = split(undef, $word);
for my $letter (@letters) {
print $letter unless exists $vowels{$letter};
}
print ' ';
}
print "\n"
Result:
$ perl delete_vowels.pl hello world
hll wrld
CodePudding user response:
An alternative and more compact method of achieving the same thing is to use the substitute operator, "s" with a regular expression that matches the vowels.
Here is an example
use strict;
use warnings;
for my $word (@ARGV)
{
print $word =~ s/[aeiou]//gri;
}
or more succinctly like this
use strict;
use warnings;
for (@ARGV)
{
print s/[aeiou]//gri;
}
Key points to note
- the regular expression uses the Character Class
[aeiou]
to match a single lower-case vowel. - the substitute operator has been given three options
- the
i
option to force a case insensitive match. This means the Character Class[aeiou]
will match both uppercase and lower-case vowels. - the
g
option to make the substitute match all instances of the regular expression -- in this instance it will match against all the vowels in the string. - the
r
option (which is a newish addition to Perl) to get the substitute operator to return the substituted string.
- the
running that gives this
$ perl try.pl hello world
hllwrld