Arithmetic calculation against Perl wildcard patterns

Using only one Perl regex expression placeholder ( s///

), as we can write below:

Each success match contains only a string of alphabetic characters A..Z

. We need to substitute the match string, which will be the sum of the character index (in alphabetical order) of each character in the match string.

Note. For A the character index will be 1, for B, 2 ... and for Z it will be 26.

See example below:

success match: ABCDMNA  
substitution result: 38  

      

Note:

1 + 2 + 3 + 4 + 13 + 14 + 1 = 38; 

      

as

A = 1, B = 2, C = 3, D = 4, M = 13, N = 14 and A = 1.

      

+3


source to share


5 answers


I'll post this as an answer, I think, although credit for coming up with an 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 academic interest, I'll post an explanation in the spoiler tags.

- We match an optional number (\d*)

followed by a letter ([A-Z])

. The number is the running amount and the letter is what we need to add to the amount.
 - Using the modifier /e

, we can do math that adds the captured number to the value of the ord()

captured letter, minus 64. The amount is returned and inserted instead of the number and letter. <w> - We use a cycle while

to rinse and repeat until all the letters are replaced and all that is left is a number. We use a while loop instead of a modifier /g

to reset the match to the beginning of the line.

+4


source


Simple split

, translate and sum

:

use strict;
use warnings;

use List::Util qw(sum);

my $string = 'ABCDMNA';

my $sum = sum map {ord($_) - ord('A') + 1} split //, $string;

print $sum, "\n";

      



Outputs:

38

      

+3


source


Can you use a modifier /e

in substitution?

$s = "ABCDMNA";
$s =~ s/(.)/$S += ord($1) - ord "@"; 1 + pos $s == length $s ? $S : ""/ge;
print "$s\n"

      

+2


source


Consider the following matching scenario:

my $text = "ABCDMNA";
my $val = $text ~= s!(\d)*([A-Z])!($1+ord($2)-ord('A')+1)!gr;

      

(Without checking it ...) This has to repeat through the string, replacing one character at a time with its ordinal value added to the current amount that was placed at the beginning. When there are no more characters, a copy ( /r

) is placed in $val

, which should contain the translated value.

+2


source


Or a 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:

  • tries to match any character

    something that should not be matched by an "empty regular expression"./.(?!)/

  • Because an empty regex matches everything, "does not follow anything", it does not always.
  • so the regex engine will jump to the next character and try again
  • this is repeated until the entire line is exhausted.
  • because we want to capture the character using the capture group /(.)(?!)/

  • (?{...})

    runs the perl code that sums the value of the captured character stored in $1

  • when regex is exhausted (and fails), the latter say $s

    prints the value of sum

from perlre

(? {code})

This zero-width assertion is executed by any embedded Perl code. This is always successful and its return value is $ ^ R.

WARNING. Using this feature safely requires that you understand its limitations. Executed code that has side effects may not perform identically from version to version due to the effect of future optimizations in the regex engine. For more information on this, see Inline Code Execution Frequency.

0


source







All Articles