# Perl Weekly Challenge 135.

My solutions (task 1, and task 2 ) to the The Weekly Challenge - 135.

``````Submitted by: Mohammad S Anwar
You are given an integer.

Write a script find out the middle 3-digits of the given
integer, if possible otherwise throw sensible error.

Example 1
Input: \$n = 1234567
Output: 345
Example 2
Input: \$n = -123
Output: 123
Example 3
Input: \$n = 1
Output: too short
Example 4
Input: \$n = 10
Output: even number of digits
``````

This seems simple enough for a oneliner: Take input from the command line, remove optional sign, get length, compute initial position, test length and output.

``````perl -E '(\$s=\$i=\$ARGV[0])=~s/^[+-]//; \$l=length \$s; \$b=(\$l-3)/2;\
say "\$i->", \$l%2==0?"Even":\$l<3?"Short":substr \$s, \$b,3;' 1234567
perl -E '(\$s=\$i=\$ARGV[0])=~s/^[+-]//; \$l=length \$s; \$b=(\$l-3)/2;\
say "\$i->", \$l%2==0?"Even":\$l<3?"Short":substr \$s, \$b,3;' -- -123
perl -E '(\$s=\$i=\$ARGV[0])=~s/^[+-]//; \$l=length \$s; \$b=(\$l-3)/2;
say "\$i->", \$l%2==0?"Even":\$l<3?"Short":substr \$s, \$b,3;' 1
perl -E '(\$s=\$i=\$ARGV[0])=~s/^[+-]//; \$l=length \$s; \$b=(\$l-3)/2;\
say "\$i->", \$l%2==0?"Even":\$l<3?"Short":substr \$s, \$b,3;' 10
``````

Results:

``````1234567->345
-123->123
1->Short
10->Even
``````

(Notice the `--` in the -123 case, so that Perl doesn’t interpret the minus sign as flagging a Perl option.)

A full program might take the desired number of digits as an additional parameter.

``````# Perl weekly challenge 135
#
use v5.12;
use warnings;
my @even_odd=qw(even odd);
say "Usage: ./ch-1.pl howmany number [number] ..." and exit unless @ARGV>1;
my \$how_many= shift @ARGV;
my \$parity=\$how_many%2; # Desire an even or an odd number of digits?
foreach my \$input(@ARGV){
(my \$digits=\$input)=~s/^[+-]//; # Remove leading sign
my \$length=length \$digits;
my \$begin=(\$length-\$how_many)/2; # initial position
my \$output=
\$digits!~/^\d+\$/        ? "Expected only digits"
:\$length%2!=\$parity? "Expected an \$even_odd[\$parity] number of digits"
:\$length<\$how_many ? "Expected more than \$how_many digits"
:substr(\$digits, \$begin, \$how_many). " (middle \$how_many digits)";
say "Input: \$input\nOutput: \$output";
}
``````

Examples:

``````./ch-1.pl 3 1234567 -123 1 10
``````

Results:

``````Input: 1234567
Output: 345 (middle 3 digits)
Input: -123
Output: 123 (middle 3 digits)
Input: 1
Output: Expected more than 3 digits
Input: 10
Output: Expected an odd number of digits
``````

Other examples:

``````./ch-1.pl 3 1234567 12345678
./ch-1.pl 4 1234567 12345678
``````

Results:

``````Input: 1234567
Output: 345 (middle 3 digits)
Input: 12345678
Output: Expected an odd number of digits
Input: 1234567
Output: Expected an even number of digits
Input: 12345678
Output: 3456 (middle 4 digits)
``````

``````Submitted by: Mohammad S Anwar
You are given 7-characters alphanumeric SEDOL.

Write a script to validate the given SEDOL. Print 1 if it is a
valid SEDOL otherwise 0.

Example 1
Input: \$SEDOL = '2936921'
Output: 1
Example 2
Input: \$SEDOL = '1234567'
Output: 0
Example 3
Input: \$SEDOL = 'B0YBKL9'
Output: 1
``````

According to the wikipedia article SEDOLS are words consisting of 7 characters. The first six are digits or consonants. The last one is a check digit. The weighted sum of the values of all the characters is congruent with 0 modulo 10 using the weights 1,3,1,7,3,9,1 and where the values are the positions occupied in the list 0..9,A..Z. I assume that lower case letters are valid and may be converted to uppercase before testing. I understand that old style SEDOLS had only digits while new style SEDOLS start with B or higher letter. Also, words starting in 9 are reserved for end user allocation; I guess they can contain consonants besides digits. If the first character is a digit other than 9, the word would correspond to an old style SEDOL, which had no letters, only digits. The first digit then indicates the origin. I use below all the information from the wikipedia page (as I understood it).

``````# Perl weekly challenge 135
#
use v5.12;
use warnings;
use List::Util qw(all sum0);
use List::MoreUtils qw(pairwise);
my @weights=(1,3,1,7,3,9,1);
my \$i=0;
my %values=map {\$_=> \$i++} 0..9,"A".."Z"; # compute weights
map {\$values{\$_}=undef} split '', "AEIOU"; # remove vowels
my %origin;
\$origin{6}="Asia or Africa";
@origin{0,3}=("UK or Ireland")x2;
@origin{4,5,7}=("Europe")x3;
\$origin{2}="America";

foreach(@ARGV){
say "Input: \$_, Output: ", is_sedol(\$_);
}
sub is_sedol {
my @s=split '', uc shift; # Assume lc is valid
return "0, Need 7 chars" unless @s==7;
return "0, Last char should be digit" unless \$s[6]=~m/\d/;
return "0, Invalid char" unless all {defined \$values{\$_}} @s; # valid chars
my @v=@values{@s};
return "0, Wrong check digit"
unless (sum0 pairwise {\$a*\$b} @weights, @v)%10==0;
return "1, End user SEDOL" if \$v[0]==9; # Assume no other restriction
return "1, New SEDOL" if \$s[0] ge 'B';
return "0, Only digits for old SEDOLs" unless  all {\$_<10} @v;
return "1, Old SEDOL, probably from \$origin{\$v[0]}" if defined \$origin{\$v[0]};
return "1, Old SEDOL, unknown origin";
}
``````

Examples:

``````./ch-2.pl 2936921 1234567 B0YBKL9
``````

Results:

``````Input: 2936921, Output: 1, Old SEDOL, probably from America
Input: 1234567, Output: 0, Wrong check digit
Input: B0YBKL9, Output: 1, New SEDOL
``````

Other examples:

``````./ch-2.pl 123 123456C ACDFGH5 1234564 9234565 92B4567 \
BCDFGH4 bcdfgh4 1C34563 0234564 1234563 2234562 \
3234561 4234560 5234569 6234568 7234567 8234566
``````

Results:

``````Input: 123, Output: 0, Need 7 chars
Input: 123456C, Output: 0, Last char should be digit
Input: ACDFGH5, Output: 0, Invalid char
Input: 1234564, Output: 0, Wrong check digit
Input: 9234565, Output: 1, End user SEDOL
Input: 92B4567, Output: 1, End user SEDOL
Input: BCDFGH4, Output: 1, New SEDOL
Input: bcdfgh4, Output: 1, New SEDOL
Input: 1C34563, Output: 0, Only digits for old SEDOLs
Input: 0234564, Output: 1, Old SEDOL, probably from UK or Ireland
Input: 1234563, Output: 1, Old SEDOL, unknown origin
Input: 2234562, Output: 1, Old SEDOL, probably from America
Input: 3234561, Output: 1, Old SEDOL, probably from UK or Ireland
Input: 4234560, Output: 1, Old SEDOL, probably from Europe
Input: 5234569, Output: 1, Old SEDOL, probably from Europe
Input: 6234568, Output: 1, Old SEDOL, probably from Asia or Africa
Input: 7234567, Output: 1, Old SEDOL, probably from Europe
Input: 8234566, Output: 1, Old SEDOL, unknown origin
``````
Written on October 20, 2021