Reputation: 119
Using just one Perl substitute regular expression statement (s///
), how can we write below:
Every success match contains just a string of Alphabetic characters A..Z
. We need to substitute the match string with a substitution that will be the sum of character index (in alphabetical order) of every character in the match string.
Note: For A, character index would be 1, for B, 2 ... and for Z would be 26.
Please see example below:
success match: ABCDMNA
substitution result: 38
Note:
1 + 2 + 3 + 4 + 13 + 14 + 1 = 38;
since
A = 1, B = 2, C = 3, D = 4, M = 13, N = 14 and A = 1.
Upvotes: 4
Views: 3245
Reputation: 63892
Or an short alternative:
echo ABCDMNA | perl -nlE 'm/(.)(?{$s+=-64+ord$1})(?!)/;say$s'
or readable
$s = "ABCDMNA";
$s =~ m/(.)(?{ $sum += ord($1) - ord('A')+1 })(?!)/;
print "$sum\n";
prints
38
Explanation:
any character
what must not followed by "empty regex". /.(?!)/
/(.)(?!)/
(?{...})
runs the perl code, what sums the value of the captured character stored in $1
say $s
prints the value of sumfrom the perlre
(?{ code })
This zero-width assertion executes any embedded Perl code. It always succeeds, and its return value is set as $^R .
WARNING: Using this feature safely requires that you understand its limitations. Code executed that has side effects may not perform identically from version to version due to the effect of future optimisations in the regex engine. For more information on this, see Embedded Code Execution Frequency.
Upvotes: 1
Reputation: 67900
I will post this as an answer, I guess, though the credit for coming up with the idea should go to abiessu for the idea presented in his answer.
perl -ple'1 while s/(\d*)([A-Z])/$1+ord($2)-64/e'
Since this is clearly homework and/or of academic interest, I will post the explanation in spoiler tags.
- We match an optional number
(\d*)
, followed by a letter([A-Z])
. The number is the running sum, and the letter is what we need to add to the sum.
- By using the/e
modifier, we can do the math, which is add the captured number to theord()
value of the captured letter, minus 64. The sum is returned and inserted instead of the number and the letter.
- We use awhile
loop to rinse and repeat until all letters have been replaced, and all that is left is a number. We use a while loop instead of the/g
modifier to reset the match to the start of the string.
Upvotes: 6
Reputation: 1927
Consider the following matching scenario:
my $text = "ABCDMNA";
my $val = $text ~= s!(\d)*([A-Z])!($1+ord($2)-ord('A')+1)!gr;
(Without having tested it...) This should repeatedly go through the string, replacing one character at a time with its ordinal value added to the current sum which has been placed at the beginning. Once there are no more characters the copy (/r
) is placed in $val
which should contain the translated value.
Upvotes: 3
Reputation: 241758
Can you use the /e
modifier in the substitution?
$s = "ABCDMNA";
$s =~ s/(.)/$S += ord($1) - ord "@"; 1 + pos $s == length $s ? $S : ""/ge;
print "$s\n"
Upvotes: 3