How to let Perl recognize both lower and uppercase input? - perl

I'm currently trying to figure out how I can make my perl script accept both the lowercase and uppercase variant of a letter.
For Example.
my %channels = (a => 'test', b => 'test2', c => 'test3', d => 'test4', e => 'test5', f => 'test6', g => 'test7');
So when I want to enter test I can either do a or A and it will accept it
To Sum up the problem:
When running the script I ran into an issue where you had to input a if you wanted test. This is all fine to me but other people wanted the option to do capital A instead. I am trying to give them the option to do either.
Thanks All

For your hash keys (single alphabet as a key) try the logical defined operator.
// => logical defined operator. If the left hand side is true give the result else if evaluate the right side.
print $channels{$input} // $channels{lc($input)};

One simple solution for your input
print $channels{lc($input)};
If the input is uppercase it will convert to lowercase. Don't get worry about lowercase characters.

It is not fully clear what your requirement is but from the example it looks like you are asking for a hash which is case insensitive regarding the keys, i.e. that $hash{foo}, $hash{FoO} etc all result in the same value.
This can be implemented with tied hashes by defining appropriate FETCH,STORE and DELETE methods for the hash. And there are already implementations which do this, like Hash::Case.
Of course you could also simply normalize all keys (lower case, upper case etc) before accessing the hash.

I would keep all the hash keys lower case and convert the input value keys to lower case:
for my $inputKey ('a', 'A', 'b', 'B') {
print $channels{lc($inputKey)}, "\n";
}

With a regex it's not shorter but another way to solve it:
my %hash = {a => 'test', b => 'test2'};
my $read_input;
foreach my $key (keys %hash){
if($key =~ /${read_input}/i){ #note the i for 'ignore case'
print $hash{$key};
}
}
You basically iterate through the keys of your hash and compare them against the input. If you found the right one you can print the value.
But nevertheless: You may just convert every input to lower case and then access the hash.

Related

Using any or none on the hash keys and values in Raku

I'm trying to use the any or none on the keys or values of a hash like that:
my %w=(a => 1, b => 2);
say %w.keys; # works
say so 'a' == %w.keys.any; # doesn't work
I've checked the Raku documentation's hash and map section but couldn't fix this issue. How to fix it? Thanks.
The code dies like this:
Cannot convert string to number: base-10 number must begin with
valid digits or '.' in '⏏a' (indicated by ⏏)
This happens because == is the numeric comparison operator, so it first tries to coerce the arguments into a number before doing the comparison.
Hash keys - at least by default - are strings, thus the eq operator for string comparison is needed here:
my %w=(a => 1, b => 2);
say so 'a' eq %w.keys.any; # True
use cmp operator when compares with string:
say so 'a' cmp %w.keys.any;

How to replace a set of search/replace pairs?

I have a dictionary of translations as a hash:
my %dict = { hello => 'hola', goodbye => 'adios' , ... }
(The actual use-case is not a human language translation! I'm replacing a load of tokens with some other values. This is just for example.)
How can I apply each of these to a string? Obviously I could loop them and pass each to s/$key/$value/ but then I'd have to quote them so it wouldn't break if a search or replacement had (for example) / in it.
In PHP there's strtr($subject, $replacement_pairs_array) - is there anything similar in Perl?
First, your hash initialization is off: A hash is initialized as a list:
my %dict = ( hello => 'hola', goodbye => 'adios' , ... );
Or you can use a hash reference:
my $dict = { hello => 'hola', goodbye => 'adios' , ... };
which is a scalar.
Replacing the keys with the values in a string is easy:
s/$_/$dict{$_}/g for keys %dict;
unless
The contents of substitutions shall not be replaced, e.g. %dict = (a => b, b => c) should transform "ab" to "bc" (not to "cc" as the above solution may or may not do, hash order is random).
The keys can contain regex metacharacters like ., +, or (). This can be circumvented by escaping regex metacharacters with the quotemeta function.
The traditional approach is to build a regex that matches all keys:
my $keys_regex = join '|', map quotemeta, keys %dict;
Then:
$string =~ s/($keys_regex)/$dict{$1}/g;
which solves all these issues.
In the regex building code, we first escape all keys with map quotemeta, and then join the strings with | to build the regex that matches all keys. The resulting regex is quite efficient.
This guarantees that each part of the string is only translated once.
%dict = ( 'hello' => 'hola', 'goodbye' => 'adios' );
my $x="hello bob, goodbye sue";
my $r=join("|",keys %dict);
$x=~s/($r)/$dict{$1}/ge;
print $x;
This shows one way to do it.
Convert the hash keys to a alternated regexp ie "hello|goodbye", look for matches with that expression then use the found key to lookup the value in the hash. With the g flag the regexp is globally or repeatedly applied to the string and the with e flag the replacement expression is evaluated as perl instead of being a literal replacement
There appears to be a CPAN module that'll do this

Difference between $map{$string} and $map->{$string} in Perl

I have a map structure in Perl, that I'm getting from some utility. The dump of which looks like this:
$VAR1 = {
'A0' => 'me_one',
'A2' => 'me_two',
'A6' => 'me_six'
}
I want to search if a particular key exists in the map. Say I would like to know if A4 is in the map.
Now if I use if (exists $map{'A4'}), I get an error during build, at $map{.
And if I use if (exists $map->{'A4'}), I get no error, and I get the desired result. However everywhere I search on the internet, to check if a key exists in a map, the syntax in Perl is if (exists $map{key})
Now my inference is that what I get from utility is not a map, though still looks like a map to me from the dump. Any one has an idea what's going on? Thank you.
Edit: Thanks to #raina77ow's answer. Adding this to further his explanation.
my %map;
print $map{key};
my $map_ref = \%map; # The reference was what the utility was returning
print $map_ref->{key};
The $map{key} line is used when you address a specific element of hash %map. For example:
my %map = (
a => 'a',
b => 'b'
);
print $map{a}; # 'a'
The $map->{key} line is used when you address a specific element of hashref $map. -> operator is used specifically to 'deference' a reference.
my $map_ref = {
a => 'a',
b => 'b'
};
print $map_ref->{a}; # 'a'
Note that in the first case the regular parenthesis are used, in the second case it's curly brackets (to define so-called anonymous hash).

Hash Key and Value in Perl

I have the question in Perl:Read a series of last names and phone numbers from the given input. The names and numbers should be separated by a comma. Then print the names and numbers alphabetically according to last name. Use hashes.
#!usr/bin/perl
my %series = ('Ashok','4365654435' 'Ramnath','4356456546' 'Aniketh','4565467577');
while (($key, $value) = each(sort %series))
{
print $key.",".$value."\n";
}
I am not getting the output. Where am I going wrong? Please help. Thanks in advance
#!usr/bin/perl
my %series = ('Ashok','4365654435' 'Ramnath','4356456546' 'Aniketh','4565467577');
print $_.",".$series{$_}."\n" for sort keys %series;
If I execute any of the above 2 programs, I get the same output as:
String found where operator expected at line 2, near "'4365654435' 'Ramnath'" (Missing operator before 'Ramnath'?)
String found where operator expected at line 2, near "'4356456546' 'Aniketh'" (Missing operator before 'Aniketh'?)
syntax error at line 2, near "'4365654435' 'Ramnath'"
Execution aborted due to compilation errors
But according to the question, I think I cannot store the input as my %series = ('Ashok','4365654435','Ramnath','4356456546','Aniketh','4565467577');
each only operates on hashes. You can't use sort like that, it sorts lists not hashes.
Your loop could be:
foreach my $key (sort keys %series) {
print $key.",".$series{$key}."\n";
}
Or in shorthand:
print $_.",".$series{$_}."\n" for sort keys %series;
In your hash declaration you have:
my %series = ('Ashok','4365654435' 'Ramnath','4356456546' 'Aniketh','4565467577');
This is generating the warnings.
A hash is simply an even list of scalars. Therefore, you have to put a comma between each pair:
my %series = ('Ashok','4365654435', 'Ramnath','4356456546', 'Aniketh','4565467577');
# ^--- ^---
If you want visual distinction between the pairs, you can use the => operator. This behaves the same as the comma. Additionaly, if the left hand side is a legal bareword, it is viewed as a quoted string. Therefore, we could write any of these:
# it is just a comma after all, with autoquoting
my %series = (Ashok => 4365654435 => Ramnath => 4356456546 => Aniketh => 4565467577);
# using it as a visual "pair" constructor
my %series = ('Ashok'=>'4365654435', 'Ramnath'=>'4356456546', 'Aniketh'=>'4565467577');
# as above, but using autoquoting. Numbers don't have to be quoted.
my %series = (
Ashok => 4365654435,
Ramnath => 4356456546,
Aniketh => 4565467577,
);
This last solution is the best. The last coma is optional, but I consider it good style—it makes it easy to add another entry. You can use autoquoting whenever the bareword on the left would be a legal variable name. E.g. a_bc => 1 is valid, but a bc => 1 is not (whitespace is not allowed in variable names), and +/- => 1 is not allowed (reserved characters). However Ünıçøðé => 1 is allowed when your source code is encoded in UTF-8 and you use uft8 in your script.
Besides what amonand Mat said, I'd like to notice other issues in your code:
your shebang is wrong it should be #!/usr/bin/perl - notice the first /
you don't have use strict; and use warnings; in your code - although this is not strictly a mistake, I consider this to be an issue. Those 2 commands will save you from a lot of trouble later on.
PS: you have to use commas between your number and names also, not only between names and numbers - you have to, because otherwise you get a compile error

What happens when you put an array on the right side of a => operator?

This might seem like a stupid question but it's been a long day. I'm an adapting some Perl code for another use and I ran across this syntax:
my #request;
#... fill the array with stuff...
my $reply = $service->call('requestMessage' => #request, $header);
That method call seems implausible, if => is just a special kind of comma and #request gets interpolated into the list.
Is it actually equivalent to:
my $reply = $service->call('requestMessage' => \#request, $header);
What's going on here?
EDIT: Thanks for the answers. I am well aware of the difference between pass by value and pass by reference. I was asking if an apparent pass by value was being converted into a pass by reference. Apparently not. Thank you all for answering.
The code in question:
my $reply = $service->call('requestMessage' => #request, $header);
is not equivalent to this:
my $reply = $service->call('requestMessage' => \#request, $header);
It is, as you surmised, equivalent to this:
my $reply = $service->call('requestMessage', #request, $header);
Sometimes, the "fat comma," as => is known, is used to indicate a relationship between positional parameters. For example, the link between the method name some_method and its intended #arguments in this code:
$server->distribute_across_nodes(some_method => #arguments);
What happens when you put an array on the right side of a => operator?
=> is the fat comma. It has no effect on the RHS. It automatically quotes the LHS if the LHS is a bareword.
The rest of your question seems to boil down to if there is a difference between passing a function an array versus a reference to an array: Yes, there is. In the first case, the array is flattened and passed to the function. So, if the array has 1,000 elements, the functions argument list will grow by 1,000 elements.
In the second case, a reference to the array is passed, so the size of the argument list does not depend on the size of the array pointed to by the reference passed to the function.
There's a school of thought that => should be used as some kind of emphatic comma, even when it makes no difference. Advocates use it to indicate that one thing describes or acts on another, e.g.:
split /,/ => $var;
Maybe the author of your code falls into this camp?
Looking at the SOAP::Lite code, it eventually makes this call
$serializer->envelope(method => shift, #_)
So your original call
$service->call('requestMessage' => #request, $header);
is just using the fat comma to emphasize that the contents of (#request, $header ) will become the parameters for the soap call requestMessage. This is less than clear, because $header is part of the parameters, but the convention doesn't make it clear. I'd say that, in this case, the fat comma is not adding anything.
I have seen the "emphatic comma" used in CGI scripts, like so (untested)
$q->param(foo => $bar)
I think it does a pretty good job there of indicating that this call will set the parameter foo. But clearly this can also be confusing. Use with caution.
It will pass "requestMessage", then all values in #request (as the 2nd, 3rd... etc. parameters), and then $header. These will probably get forced into a hash.
Here's an example:
perl -MData::Dumper -e '#a = (1, 2, 3, 4);
%b = ('a' => #a, 'c');
print Dumper(\%b);'
$VAR1 = {
'4' => 'c',
'a' => 1,
'2' => 3
};
So in this case it's the same as
%b = ('a' => 1, 2 => 3, 4 => 'c');