File Coverage

blib/lib/Algorithm/Damm.pm
Criterion Covered Total %
statement 22 22 100.0
branch 12 12 100.0
condition n/a
subroutine 5 5 100.0
pod 2 2 100.0
total 41 41 100.0


line stmt bran cond sub pod time code
1             package Algorithm::Damm;
2              
3 4     4   103421 use strict;
  4         10  
  4         164  
4 4     4   23 use Exporter;
  4         7  
  4         972  
5              
6 4     4   22 use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK $ERROR/;
  4         17  
  4         1808  
7              
8             @ISA = qw/Exporter/;
9             @EXPORT = qw//;
10             @EXPORT_OK = qw/check_digit is_valid/;
11              
12             $VERSION = '1.001.002';
13              
14             =pod
15              
16             =head1 NAME
17              
18             Algorithm::Damm - Calculate the Damm error correction check digit.
19              
20             =head1 SYNOPSIS
21              
22             use Algorithm::Damm qw/check_digit is_valid/;
23              
24             $c = check_digit("43881234567");
25             print "It works\n" if is_valid("43881234567$c");
26              
27             =head1 DESCRIPTION
28              
29             This module implements the Damm algorithm for calculating a check
30             digit.
31              
32             You can find information about the algorithm by searching the web for
33             "Damm ECC". In particular, see the L section (below).
34              
35             =head1 FUNCTIONS
36              
37             =over 4
38              
39             =cut
40              
41             =item is_valid CHECKSUMMED_NUM
42              
43             This function returns 1 if the final character of CHECKSUMMED_NUM is
44             the correct checksum for the rest of the number, 0 if not, and undef
45             if CHECKSUMMED_NUM contains an invalid character or does not contain
46             at least two digits (one for the number, and one for the checksum).
47              
48             This function is equivalent to
49              
50             substr $N,length($N)-1 eq check_digit(substr $N,0,length($N)-1)
51              
52             Additionally, due to the way this algorithm works, if you crank the
53             checksum calculation through the last digit (checkdigit included), you
54             will end up with a value of 0.
55              
56             =cut
57              
58             sub is_valid {
59 48     48 1 12699 my $N = shift;
60              
61 48 100       122 return undef unless defined( $N );
62 47 100       108 return undef unless length( $N ) >= 2;
63 44 100       168 return undef unless $N =~ /^\d+$/;
64              
65 42         150 return check_digit( $N ) == 0;
66             }
67              
68             =item check_digit NUM
69              
70             This function returns the checksum of the given number. It will
71             return undef if it is not able to calculate the checksum.
72              
73             =cut
74              
75             {
76             # This table is defined at
77             # http://en.wikipedia.org/wiki/Damm_algorithm
78             my @table = (
79             [ qw( 0 3 1 7 5 9 8 6 4 2 ) ],
80             [ qw( 7 0 9 2 1 5 4 8 6 3 ) ],
81             [ qw( 4 2 0 6 8 7 1 3 5 9 ) ],
82             [ qw( 1 7 5 0 9 8 3 4 2 6 ) ],
83             [ qw( 6 1 2 3 0 4 5 9 7 8 ) ],
84             [ qw( 3 6 7 4 2 0 9 5 8 1 ) ],
85             [ qw( 5 8 6 9 7 2 0 1 3 4 ) ],
86             [ qw( 8 9 4 5 3 6 2 0 1 7 ) ],
87             [ qw( 9 4 3 8 6 1 7 2 0 5 ) ],
88             [ qw( 2 5 8 1 4 3 6 7 9 0 ) ],
89             );
90              
91             sub check_digit {
92 60     60 1 7560 my $N = shift;
93              
94 60 100       129 return undef unless defined( $N );
95 59 100       119 return undef unless length( $N );
96 58 100       220 return undef unless $N =~ /^\d+$/;
97              
98 56         65 my $c = 0;
99 56         181 my @digits = split(//, $N);
100 56         313 $c = $table[$c][$_] for @digits;
101              
102 56         320 return $c;
103             }
104             }
105              
106             =back
107              
108             =cut
109              
110             1;
111              
112             __END__