perl6 Is using junctions in matching possible? - match

Is it possible to use junction to match any of the values in a junction? I want to match any of the values in an array. What is the proper way to do it?
lisprog$ perl6
To exit type 'exit' or '^D'
> my #a=<a b c>
[a b c]
> any(#a)
any(a, b, c)
> my $x=any(#a)
any(a, b, c)
> my $y = "a 1"
a 1
> say $y ~~ m/ $x /
False
> say $y ~~ m/ "$x" /
False
> my $x = any(#a).Str
any("a", "b", "c")
> say $y ~~ m/ $x /
False
> say $y ~~ m/ || $x /
False
> say $y ~~ m/ || #a /
「a」
>
Thanks !!

Junctions are not meant to be interpolated into regexes. They're meant to be used in normal Perl 6 expressions, particularly with comparison operators (such as eq):
my #a = <x y z>;
say "y" eq any(#a); # any(False, True, False)
say so "y" eq any(#a); # True
To match any of the values of an array in a regex, simply write the name of the array variable (starting with #) in the regex. By default, this is interpreted as an | alternation ("longest match"), but you can also specify it to be a || alternation ("first match"):
my #a = <foo bar barkeep>;
say "barkeeper" ~~ / #a /; # 「barkeep」
say "barkeeper" ~~ / || #a /; # 「bar」

Related

How to tell if a string can be transformed into another string by removing or uppercasing lowercase letters?

In perl, I have two input strings, for this example, ahueFFggLKy and HFFGLK. I want to be able to iterate through all of the possible combinations of my input without lowercase letter groups (a, h, u, e, g...ah, au...hegy, etc) so in each iteration lowercase letters are removed and the remaining lowercase letters are uppercased:
ah:
ueFFggLKy (UEFFGGLKY)
^^
au:
h eFFggLKy (HEFFGGLKY)
^ ^
hegy:
a u FF gLKy | a u FFg LKy (AUFFGLKY)
^ ^ ^ | ^ ^ ^
auegy:
h FF gLK | h FFg LK (HFFGLK)
^ ^^ ^ ^ ^ ^^ ^ ^ -^--^-
The last option (auegy) is the answer, and I want to be able to iterate over letters to determine if I am able to convert ahueFFggLKy to HFFGLK without modifying any of the capital letters. This example would return "YES".
If inputs like fOoBar and BAR come up, I am not successfully able to convert fOoBar to BAR because the O in fOoBar is capitalized. My program would return "NO".
Can someone provide me with a perl example of how this would be done?
I think I have understood your requirement: the first string may be transformed by either deleting or upper-casing any lower-case letter, and you wish to know whether the second string can be derived from the first in this way
I suggest that you can transform the second string to a regex pattern to achieve this. If every upper-case letter in the second string must be matched by the corresponding upper or lower-case letter in the first, with any number of intervening lower-case letters, then the transformation is possible. Otherwise it is not
This program implements the idea
use strict;
use warnings 'all';
use feature 'say';
my #pairs = (
[ qw/ ahueFFggLKy HFFGLK / ],
[ qw/ fOoBar BAR / ],
);
for my $pair ( #pairs ) {
my ($s1, $s2) = #$pair;
printf "%s => %s -- %s\n", $s1, $s2, contains($s1, $s2) ? 'YES' : 'NO';
}
sub contains {
my ($s1, $s2) = #_;
my $re = join ' \p{Ll}* ', map { "(?i: $_ )" } $s2 =~ /\p{Lu}/g;
$re = qr/ ^ \p{Ll}* $re \p{Ll}* $ /x;
$s1 =~ $re;
}
output
ahueFFggLKy => HFFGLK -- YES
fOoBar => BAR -- NO
To read an array like #pairs from STDIN you could write something like this
my #pairs;
{
local $/;
my #input = split ' ', <>;
push #pairs, [ splice #input, 0, 2 ] while #input > 1;
}
Kind of unelegant solution, but it seems to output what you need.
#!/usr/bin/perl
use warnings;
use strict;
use List::Util qw{ all };
my ($str1, $str2) = qw( ahueFFggLKy HFFGLK );
my #small_indices;
push #small_indices, pos($str1) - 1 while $str1 =~ /[[:lower:]]/g;
my #present = (0) x #small_indices;
until (all { $_ } #present) {
my $try = $str1;
for my $i (reverse 0 .. $#present) {
substr $try, $small_indices[$i], 1,
$present[$i] ? substr $str1, $small_indices[$i], 1
: q();
}
if (uc $try eq $str2) {
print $present[$_] ? q() : substr $str1, $small_indices[$_], 1
for 0 .. $#present;
print ":\n";
my $j = 0;
for my $i (0 .. length($str1) - 1) {
my $char = substr $str1, $i, 1;
if ($char eq uc $char || $present[$j++]) {
print $char;
} else {
print '.';
}
}
print "\n";
}
my $idx = 0;
$present[$idx] = 0, ++$idx while $present[$idx];
$present[$idx] = 1;
}
It builds an indicator function #present, which say what lowercase letters are present in the string. All possible values of #present are iterated by adding 1 to the binary number corresponding to the function.

Why we can not use "le" in for loop and can use in "if condition"

I've made this program as a beginner. Need to clarify something!
Why I m not able to use "le" in a for loop given below but I'm able to use it in "if condition". What is the reason behind that. ?
print "Type the number upto series should run\n";
my $var;
$var = int<STDIN>;
chomp $var;
my ($i, $t);
my $x = 0;
my $y = 1;
if($var eq 1) {
print "\nYour Series is : $x\n";
} elsif($var eq 2){
print "\nYour Series is : $x $y\n";
} elsif($var ge 2) {
print "Your Series is : $x $y ";
for($i = 1; $i le $var - 2; $i++) {
# Why the condition not working when I'm using "le"
# but it does work when I'm using "<="
$t = $x + $y;
$x = $y;
$y = $t;
print "$t ";
}
print "\n";
} else {
print "Error: Enter a valid postive integer\n";
}
You are free to use le and <= as you like. But you should be aware that they are completely different operators.
Numeric comparision operators are
== != < <= > >= <=>
The equivalent string comparision operators are
eq ne lt le gt ge cmp
Strings and numbers are converted to each other as needed. This means for example that
3 ge 20 # true: 3 is string-greater than 20
11 le 2 # true: 11 is string-less-or-equal than 2
because lexicographic ordering compares character by character. Using the numeric operators when you want to treat the contents of your $variables as numbers is therefore preferable and will yield the correct results.
Note that Perl translates between strings and numbers invisibly. It is advisable to use warnings, so that you get a helpful message when a string can't represent a number (e.g. "a").
The correct answer has been given, that ge does string comparison, where for example 11 is considered less than 2. The solution is to use numerical comparison, == and >=.
I thought I would help demonstrate the problem you are having. Consider this demonstration of how the default sort works:
$ perl -le 'print for sort 1 .. 10'
1
10
2
3
4
5
6
7
8
9
As you can see, it considers 10 lower than 2, and that is because of string comparison, which is the default mode for sort. This is how the default sorting routine looks under the hood:
sort { $a cmp $b }
cmp belongs to the string comparison operators, like eq, le, and ge. These operators are described here (cmp is below that).
For the sort routine to do what we expect in the above example, we would have to use a numeric comparison operator, which is the "spaceship operator" <=>:
sort { $a <=> $b }
In your case, you can try out your problem with this one-liner:
$ perl -nlwe 'print $_ ge 2 ? "Greater or equal" : "Lesser"'
1
Lesser
2
Greater or equal
3
Greater or equal
11
Lesser
When you compare numbers with eq, le, gt..... etc; they first be converted to string. And strings will be checkd for alphabatical order, so "11" will be less then "2" here.
So you should be using ==,<=,>= ...etc when comparing numbers.
I thought you may like to see a more Perl-like program that produces the Fibonnaci series like yours.
use strict;
use warnings;
print "Type the length of the series\n";
chomp(my $length = <>);
unless ($length and $length !~ /\D/ and $length > 0) {
print "Error: Enter a positive integer\n";
}
print "\n";
my #series = (0, 1);
while (#series < $length) {
push #series, $series[-2] + $series[-1];
}
print "#series[0..$length-1]\n";

Why if/elsif in Perl execute only the first block?

I am new to Perl. I have an assignment to write a Perl program that accept a countable word from a command line and then generates its plural form. I have composed the following code below, and it shows no errors of compilation. When I execute it from the command line:
(perl plural.pl, for example), it prompts me to enter a noun, then whatever noun I feed as input, the plural form is the same. It doesn't execute the remaining if statements.
For example, if I enter the word "cat", the plural is generated as "cats". But when I enter the word 'church', for example, the plural is generated as 'churches', "fly" as "flys".
Here is the code:
#!/usr/bin/perl
$suffix1 = 's';
$suffix2 = 'es';
$suffix3 = 'ies';
print "Enter a countable noun to get plural: ";
$word = <STDIN>;
chomp($word);
if(substr $word, -1 == 'b' or 'd' or 'c' or 'g' or 'r' or 'j' or 'k' or 'l' or 'm' or 'n' or 'p' or 'q' or 'r' or 't' or 'v' or 'w' or 'e' or 'i' or 'o' or 'u') {
$temp = $word.$suffix1;
print "The plural form of the word \"$word\" is: $temp \n";
}
elsif (substr $word, -1 == 's' or 'sh' or 'ch' or 'x' or 'z') {
$temp = $word.$suffix2;
print "The plural form of the word \"$word\" is: $temp \n";
}
elsif (substr $word, -1 == 'y') {
chop($word);
$temp = $word.$suffix3;
print "The plural form of the word \"$word\" is: $temp \n";
}
Could you help me making the code execute the three statements.
First of all, always use use strict; use warnings;.
Strings are compared using eq, not ==.
substr $word, -1 eq 'b' means substr $word, (-1 eq 'b') when you meant substr($word, -1) eq 'b'. You'll face lots of problems if you omit parens around function calls.
substr($word, -1) eq 'b' or 'd' means the same as (substr($word, -1) eq 'b') or ('d'). 'd' is always true. You'd need to use substr($word, -1) eq 'b' or substr($word, -1) eq 'd'. (Preferably, you'd save substr $word, -1 in a variable to avoid doing it repeatedly.)
substr $word, -1 will never equal ch or sh.
The match operator makes this easy:
if ($word =~ /[bdcgrjklmnpqrtvweiou]\z/) {
...
}
elsif ($word =~ /(?:[sxz]|[sc]h)\z/) {
...
}
elsif ($word =~ /y\z/) {
...
}
In Perl, we use eq for string comparison instead of ==.
You can't use or like this. It should be like if (substr($word, -1) eq 'b' or substr ($word, -1) eq 'd'). Otherwise you could use an array containing all the string that you would like to compare and grep from that array.
Duskast is right. Perl uses symbols for numeric comparisons, and strings for string comparisons.
== eq
!= ne
< lt
<= le
> gt
>= ge
<=> cmp
Also, your use of or, though a good try, doesn't work. The keyword or has weak precedence, and so the expression
substr $word, -1 == 'b' or 'd' or 'c' or
'g' or 'r' or 'j' or
'k' or 'l' or 'm' or
'n' or 'p' or 'q' or
'r' or 't' or 'v' or
'w' or 'e' or 'i' or
'o' or 'u'
is interpreted as
substr ($word, (-1 == 'b')) or 'd' or 'c' or
'g' or 'r' or 'j' or
'k' or 'l' or 'm' or
'n' or 'p' or 'q' or
'r' or 't' or 'v' or
'w' or 'e' or 'i' or
'o' or 'u'
I'm not sure what the substr works out to, but if it's false, the expression continues to the or 'b', which is interpreted as true. Have you seen regular expressions yet? This is much more idiomatically done as
if ($word =~ /[bdcgrjklmnpqrtvweiou]$/) {...}
# Does $word match any of those characters followed by
# the end of the line or string?
Look in the Perl docs for string substitution and the s/.../.../ construct.
By the way, if you were paid to do this instead of being a student, you'd use the Lingua modules instead.
First of all, always, always include use strict; and use warnings;.
Second, use indentations. I've taught Perl courses at work and refuse to accept any assignment that was not indented correctly. In fact, I'm very, very strict about this because I want users to learn to code to the standard (4 space indent, etc.). It makes your program easier to read and to support.
While we're at it, break overly long lines -- especially on StackOverflow. It's hard to read a program when you have to scroll back and forth.
Quick look at your program:
In Perl, strings and numerics use two different sets of boolean operations. This is because strings can contain only digits, but still be strings. Imagine inventory item numbers like 1384 and 993. If I'm sorting these as strings, the 1384 item comes first. If I am sorting them numerically, 993 should come first. Your program has no way of knowing this except by the boolean operation you use:
Boolean Operation Numeric String
================= ======= ======
Equals == eq
Not Equals != ne
Greater Than > gt
Less Than < lt
Greater than/Equals >= ge
Less than/Equals <= le
THe other is that an or, and, || and && only work with two booleans. This won't work:
if ( $a > $b or $c ) {
What this is saying is this:
if ( ( $a > $b ) or $c ) {
So, if $c is a non-zero value, then $c will be true, and the whole statement would be true. You have to do your statement this way:
if ( $a > $b or $a > $c ) {
Another thing, use qq(..) and q() when quoting strings that contain quotation marks. This way, you don't have to put a backslash in front of them.
print "The word is \"swordfish\"\n";
print qq(The word is "swordfish"\n);
And, if you use use feature qw(say); at the top of your program, you get the bonus command of say which is like print, except the ending new line is assumed:
say qq(The word is "swordfish");
When you use substr, $foo, -1, you are only looking at the last character. It cannot ever be a two character string:
if ( substr $word, -1 eq "ch" ) {
will always be false.
Long ifs are hard to maintain. I would use a for loop (actually not, but let's pretend for now..):
#! /usr/bin/env perl
#
# Use these in ALL of your programs
#
use strict;
use warnings;
use feature qw(say);
#
# Use better, more descriptive names
#
my $standard_plural_suffix = 's';
my $uncommon_plural_suffix = 'es';
my $y_ending_plural_suffix = 'ies';
print "Enter a countable noun to get plural: ";
chomp (my $word = <STDIN>);
my $plural_form;
#
# Instead of a long, long "if", use a for loop for testing. Easier to maintain
#
for my $last_letter qw( b d c g r j k l m n p q r t v w e i o u) {
if ( substr($word, -1) eq $last_letter ) {
$plural_form = $word . $standard_plural_suffix;
last;
}
}
#
# Is it an "uncommon plural" test (single character)
#
if ( not $plural_form ) {
for my $last_letter qw(s x z) {
if ( substr($word, -1) eq $last_letter ) {
$plural_form = $word . $uncommon_plural_suffix;
last;
}
}
}
#
# Is it an "uncommon plural" test (double character)
#
if ( not $plural_form ) {
for my $last_two_letters qw(sh ch) {
if ( substr($word, -2) eq $last_two_letters ) {
$plural_form = $word . $uncommon_plural_suffix;
last;
}
}
}
if ( not $plural_form ) {
if ( substr($word, -1) eq 'y' ) {
chop ( my $chopped_word = $word );
$plural_form = $chopped_word . $y_ending_plural_suffix;
}
}
if ( $plural_form ) {
say qq(The plural of "$word" is "$plural_form");
}
else {
say qq(Could not find plural form of "$word");
}
Do you know about regular expressions? Those would work a lot better than using substr because you can test multiple things at once. Plus, I wouldn't use chop, but a regular expression substitution:
#! /usr/bin/env perl
#
# Use these in ALL of your programs
#
use strict;
use warnings;
use feature qw(say);
#
# Use better, more descriptive names
#
my $standard_plural_suffix = 's';
my $uncommon_plural_suffix = 'es';
my $y_ending_plural_suffix = 'ies';
print "Enter a countable noun to get plural: ";
chomp (my $word = <STDIN>);
my $plural_form;
#
# Standard plural (adding plain ol' 's'
#
if ( $word =~ /[bdcgrjklmnpqrtvweiou]$/ ) {
$plural_form = $word . $standard_plural_suffix;
}
#
# Uncommon plural (adding es)
#
elsif ( $word =~ /([sxz]|[sc]h)$/ ) {
$plural_form = $word . $uncommon_plural_suffix;
}
#
# Final 'y' rule: Replace y with ies
#
elsif ( $word =~ /y$/ ) {
$plural_form = $word;
$plural_form =~ s/y$/ies/;
}
if ( $plural_form ) {
say qq(The plural of "$word" is "$plural_form");
}
else {
say qq(Could not find plural form of "$word");
}
I have changed your code a bit. I'm using regular expression:
#!/usr/bin/perl
$suffix1 = 's';
$suffix2 = 'es';
$suffix3 = 'ies';
print "Enter a countable noun to get plural: ";
$word = <STDIN>;
chomp($word);
if ( $word =~ m/(s|sh|ch|x|z)$/) {
$temp = $word . $suffix2;
}
elsif ( substr( $word, -1 ) eq 'y' ) {
chop($word);
$temp = $word . $suffix3;
}
else {
$temp = $word . $suffix1;
}
print "The plural form of the word \"$word\" is: $temp \n";
Also I recommend you always use strict; and use warnings;

Why does #array ~~ LIST return false even though #array contains the same elements as LIST?

I have
#a = (1,2,3); print (#a ~~ (1,2,3))
and
#a = (1,2,3); print (#a == (1,2,3))
The first one is the one I expect to work, but it does not print anything. The second one does print 1.
Why? Isn't the smart matching operator ~~ supposed to match in the case of #a ~~ (1,2,3)?
For a second, lets consider the slightly different
\#a ~~ (1,2,3)
~~ evaluates its arguments in scalar context, so the above is the same as
scalar(\#a) ~~ scalar(1,2,3)
\#a (in any context) returns a reference to #a.
1, 2, 3 in scalar context is similar to do { 1; 2; 3 }, returning 3.
So minus a couple of warnings*, the above is equivalent to
\#a ~~ 3
What you actually want is
\#a ~~ do { my #temp = (1,2,3); \#temp }
which can be shortened to
\#a ~~ [ 1,2,3 ]
Finally, the magic of ~~ allows \#a to be written as #a, so that can be shortened further to
#a ~~ [ 1,2,3 ]
* — Always use use strict; use warnings;!
Smart match tries to do what I think you're expecting if you use an array or an array reference on the right side -- but not a list.
$ perl -E '#a = (1, 2, 3); say (#a ~~ (1, 2, 3))'
$ perl -E '#a = (1, 2, 3); say ((1, 2, 3) ~~ #a)' # also misguided, but different
1
$ perl -E '#a = (1, 2, 3); say (#a ~~ [1, 2, 3])'
1
Start with What is the difference between a list and an array? in the perlfaq. It specifically shows you how your choice of values is wrong.
You might also start by writing out why you expected each to work or not work, so that we might correct your expectations. Why did you think you'd get the results that you expected?
As for the smart match bits, there's no rule for ARRAY ~~ LIST. The smart match only works with the pairs enumerated in its table in perlsyn. It's going to force it to be one of those pairs.
When you run into these problems, try many more cases:
#!perl
use v5.10.1;
use strict;
use warnings;
my #a = (1,2,3);
say "\#a is #a";
say "\#a ~~ (1,2,3) is ", try( #a ~~ (1,2,3) );
say "\#a ~~ [1,2,3] is ", try( #a ~~ [1,2,3] );
say "\#a ~~ 3 is ", try( #a ~~ 3 );
say "3 ~~ \#a is ", try( 3 ~~ #a );
say '';
my #b = (4,5,6);
say "\#b is #b";
say "\#b ~~ (4,5,6) is ", try( #b ~~ (4,5,6) );
say "\#b ~~ [4,5,6] is ", try( #b ~~ [4,5,6] );
say "\#b ~~ 3 is ", try( #b ~~ 3 );
say "3 ~~ \#b is ", try( 3 ~~ #b );
say '';
say "\#b ~~ \#a is ", try( #b ~~ #a );
sub try { $_[0] || 0 }
The output of the various cases is the clue that you misread the docs:
Useless use of a constant (2) in void context at test.pl line 8.
Useless use of a constant (4) in void context at test.pl line 17.
Useless use of a constant (5) in void context at test.pl line 17.
#a is 1 2 3
#a ~~ (1,2,3) is 0
#a ~~ [1,2,3] is 1
#a ~~ 3 is 0
3 ~~ #a is 1
#b is 4 5 6
#b ~~ (4,5,6) is 0
#b ~~ [4,5,6] is 1
#b ~~ 3 is 0
3 ~~ #b is 0
#b ~~ #a is 0

perl :"//" operator?

I have a question about using "//" operator, my testing code is as following:
perl -e '#arr1=();#arr2=(1,2,3);#arr3=defined(#arr1)?#arr1:#arr2;print "[#arr3]\n"'
[1 2 3]
perl -e '#arr1=();#arr2=(1,2,3);#arr3=#arr1//#arr2;print "[#arr3]\n"'
[0]
perl -e '$v1=();$v2="123";$v3=defined($v1)?$v1:$v2;print "[$v3]\n"'
[123]
perl -e '$v1=();$v2="123";$v3=$v1//$v2;print "[$v3]\n"'
[123]
my question is, why do using "//" operator give the same results as using "defined()? : " on the scalar, but not array(or hash)?
Thanks!!!
Because the leftmost operand of ?:, ||, or && — or this newfanglulated // thingie — is always evaluated in boolean not list context, whereas the other operands inherit the surrounding context.
#a = #b && #c;
means
if (#b) {
#a = #c;
} else {
#a = scalar #b;
}
While
#a = #b || #c;
and also
#a = #b // #c;
both mean
means
if (#b) {
#a = scalar #b;
} else {
#a = #c;
}
The only way to get rid of the scalar in assigning #b to #a is to use ?:
#a = #b ? #b : #c;
which of course means
if (#b) {
#a = #b;
} else {
#a = #c;
}
There is also the property that ?: can be an lvalue:
(#a > #b ? #a : #b) = #c;
which of course means
if (#a > #b) {
#a = #c;
} else {
#b = #c;
}
EDIT
The implementation of #a // #b and its definition differ. Bug submitted. Thanks.
This has more to do with defined than with //. From perldoc -f defined:
Use of defined on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate had ever been allocated. This behavior may disappear in future versions of Perl.
So in your first example, defined(#arr1) is false; in the second, defined(#arr1) is true, and #arr3 contains scalar(#arr1). The difference between // and defined($a) ? $a : $b is noted in perldoc perlop:
Although it has no direct equivalent in C, Perl's // operator is related to its C-style or. In fact, it's exactly the same as ||, except that it tests the left hand side's definedness instead of its truth. Thus, $a // $b is similar to defined($a) || $b (except that it returns the value of $a rather than the value of defined($a)) and yields the same result as defined($a) ? $a : $b (except that the ternary-operator form can be used as a lvalue, while $a // $b cannot). This is very useful for providing default values for variables. If you actually want to test if at least one of $a and $b is defined, use defined($a // $b).
(Emphasis mine.)
So for example:
(defined($a) ? $a : $b) = $c; # This is valid.
($a // $b) = $c; # This is not.