in reply to I'm struggling with a function, and hoping for some insight -- not strictly Perl

Your function considers an input string as valid, if (after sanitizing) it either matches a certain regex, or passes a certain check digit algorithm.

There are many standardized check digit algorithms in use; if you need to find out which one you're dealing with here, maybe this Wikipedia page can help.
Edit: As it turns out, it's the Luhn algorithm.

Anyway, here is a more or less literal translation of your code to to Perl with many explanatory comments (keeping in mind that I had to make an educated guess about the non-standard function discussed in a separate answer above):

#!/usr/bin/perl use strict; use warnings; use feature 'say'; sub validate_serial_number { my $v = shift; $v =~ s/\s//g; # remove whitespace $v = uc $v; # convert to uppercase # 1) Try regex: return 0 if !length $v; return 1 if $v =~ /^JM-\d+-\S{4}[1-9Zz]{6}$/; # 2) Initialize the %map hash with (A=>0, B=>1, C=>2, ...): my $dv = 0; my %map = map { $_ => $dv++ } qw(A B C D E F G H J K L M N P Q R T U V W Y 3 4 6 7 8 9); # 3) Extract significant character data, for example: # 'FOOBAR123ABCDE' -> chars: qw(D C B A 3 R A B F) # check: 'E' my @chars = reverse split '', $v; my $check = shift @chars; @chars = grep { exists $map{$_} } @chars; # 4) Sanity check: return 0 if @chars != 9; # 5) Perform check digit algorithm: my $totalVal = 0; # Loop over the reversed array of input characters: for my $i (0..$#chars) { # Map the character to a unique numeric value: my $posVal = $map{$chars[$i]}; # Double the value, but only for every second character: $posVal *= 2 if !($i % 2); # Add the sum of the digits of $posVal to $totalVal: while($posVal){ $totalVal += $posVal % 10; $posVal = int($posVal / 10); } } # Substract the last digit of $totalVal from 10, and take the # last digit of *that* to get the check digit: return ( $check eq ( 10 - $totalVal % 10 ) % 10 ); } for ('Foo abr 123 ABCD6', 'Foo bar 123 ABCD6') { say "'$_' is " . (validate_serial_number($_) ? "valid" : "invalid"); }

Output:

'Foo abr 123 ABCD6' is invalid 'Foo bar 123 ABCD6' is valid

Replies are listed 'Best First'.
Re^2: I'm struggling with a function, and hoping for some insight -- not strictly Perl
by taint (Chaplain) on May 18, 2014 at 21:42 UTC
    Hello, smls, and thank you VERY much for an over-the-top reply!
    The Points Fairy thought so too. :)

    In all fairness to anyone looking to respond; I should have probably noted in the OP, that I think my difficulty in following the logic, or flow, seemed to be with my apparent lack of knowledge with the map function. The use of split in the code here, might also be a factor. But, where split is concerned, may well be related to my lack of experience with map, or because this is in JavaScript, not Perl.

    Thanks again, smls, for such an informative reply!

    --Chris

    ¡λɐp ʇɑəɹ⅁ ɐ əʌɐɥ puɐ ʻꜱdləɥ ꜱᴉɥʇ ədoH