Hi, do you guys ever work with Verhoeff check digit algorithm (https://en.wikipedia.org/wiki/Verhoeff_algorithm) with SAS? I am trying to use sas for verhoeff check digit but havent found any script to do so.
You're welcome. Only a few small changes (highlighted in bold below) to the previous code are needed to create a new function VCDVAL that returns 1 if the last digit of the argument is the correct Verhoeff check digit and 0 otherwise:
/* Validate a check digit from a digit string S according to the Verhoeff algorithm, using tables and formulas from https://en.wikipedia.org/wiki/Verhoeff_algorithm (2024-05-17) */ proc fcmp outlib=work.funcs.test; function vcdval(s $); array d[10,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 2 3 4 0 6 7 8 9 5 2 3 4 0 1 7 8 9 5 6 3 4 0 1 2 8 9 5 6 7 4 0 1 2 3 9 5 6 7 8 5 9 8 7 6 0 4 3 2 1 6 5 9 8 7 1 0 4 3 2 7 6 5 9 8 2 1 0 4 3 8 7 6 5 9 3 2 1 0 4 9 8 7 6 5 4 3 2 1 0); array v[10] /nosymbols (0 4 3 2 1 5 6 7 8 9); array p[8,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 5 7 6 2 8 3 0 9 4 5 8 0 3 7 9 6 1 4 2 8 9 1 6 0 4 3 5 2 7 9 4 5 3 1 2 6 8 7 0 4 2 8 6 5 7 3 9 0 1 2 7 9 3 8 0 6 4 1 5 7 0 4 6 9 1 3 2 5 8); array n[1] /nosymbols; k=length(s); call dynamic_array(n, k); do i=1 to k; n[i]=input(char(s,k-i+1),1.); end; c=0; do i=1 to k; c=d[c+1,p[mod(i-1,8)+1,n[i]+1]+1]; end; val=(c=0); return(val); endsub; run; options cmplib=work.funcs; /* Example */ data _null_; if vcdval('2363') then put 'Check digit is correct.'; else put 'Check digit is wrong.'; run;
Having the two functions in place, it's easy to check their consistency on, say, one million random digit strings with lengths ranging from 1 to, e.g., 40:
358 data _null_; 359 call streaminit('MT64',27182818); 360 length s $40; 361 do i=1 to 1e6; 362 s=' '; 363 do j=1 to rand('integer',40); 364 substr(s,j,1)=put(rand('integer',0,9),1.); 365 end; 366 if vcdval(cats(s,vcd(s)))=0 then do; 367 put 'ER' 'ROR: Wrong check digit encountered for ' s=; 368 stop; 369 end; 370 end; 371 run; NOTE: DATA statement used (Total process time): real time 20.93 seconds cpu time 20.79 seconds
Hi @febyinka and welcome to the SAS Support Communities!
Thank your very much for sharing this interesting link.
@febyinka wrote:
I am trying to use sas for verhoeff check digit but havent found any script to do so.
In this situation I would try and write my own function using PROC FCMP, as shown below.
/* Compute a check digit from a digit string S according to the Verhoeff algorithm,
using tables and formulas from https://en.wikipedia.org/wiki/Verhoeff_algorithm (2024-05-17) */
proc fcmp outlib=work.funcs.test;
function vcd(s $);
array d[10,10] /nosymbols (0 1 2 3 4 5 6 7 8 9
1 2 3 4 0 6 7 8 9 5
2 3 4 0 1 7 8 9 5 6
3 4 0 1 2 8 9 5 6 7
4 0 1 2 3 9 5 6 7 8
5 9 8 7 6 0 4 3 2 1
6 5 9 8 7 1 0 4 3 2
7 6 5 9 8 2 1 0 4 3
8 7 6 5 9 3 2 1 0 4
9 8 7 6 5 4 3 2 1 0);
array v[10] /nosymbols (0 4 3 2 1 5 6 7 8 9);
array p[8,10] /nosymbols (0 1 2 3 4 5 6 7 8 9
1 5 7 6 2 8 3 0 9 4
5 8 0 3 7 9 6 1 4 2
8 9 1 6 0 4 3 5 2 7
9 4 5 3 1 2 6 8 7 0
4 2 8 6 5 7 3 9 0 1
2 7 9 3 8 0 6 4 1 5
7 0 4 6 9 1 3 2 5 8);
array n[1] /nosymbols;
k=length(s);
call dynamic_array(n, k);
do i=1 to k;
n[i]=input(char(s,k-i+1),1.);
end;
c=0;
do i=1 to k;
c=d[c+1,p[mod(i,8)+1,n[i]+1]+1];
end;
cd=v[c+1];
return(cd);
endsub;
run;
options cmplib=work.funcs;
/* Example */
data _null_;
x=vcd('236');
put 'Check digit = ' x;
run;
Result: 3.
Excellent approach by @FreelanceReinh. It reminds me of a challenge I had years ago in validating NPI (national provider identity) numbers, which relies on the Luhn algorithm. I also created an FCMP version!
Hi Thank You it was great and working perfectly!!
You're welcome. Only a few small changes (highlighted in bold below) to the previous code are needed to create a new function VCDVAL that returns 1 if the last digit of the argument is the correct Verhoeff check digit and 0 otherwise:
/* Validate a check digit from a digit string S according to the Verhoeff algorithm, using tables and formulas from https://en.wikipedia.org/wiki/Verhoeff_algorithm (2024-05-17) */ proc fcmp outlib=work.funcs.test; function vcdval(s $); array d[10,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 2 3 4 0 6 7 8 9 5 2 3 4 0 1 7 8 9 5 6 3 4 0 1 2 8 9 5 6 7 4 0 1 2 3 9 5 6 7 8 5 9 8 7 6 0 4 3 2 1 6 5 9 8 7 1 0 4 3 2 7 6 5 9 8 2 1 0 4 3 8 7 6 5 9 3 2 1 0 4 9 8 7 6 5 4 3 2 1 0); array v[10] /nosymbols (0 4 3 2 1 5 6 7 8 9); array p[8,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 5 7 6 2 8 3 0 9 4 5 8 0 3 7 9 6 1 4 2 8 9 1 6 0 4 3 5 2 7 9 4 5 3 1 2 6 8 7 0 4 2 8 6 5 7 3 9 0 1 2 7 9 3 8 0 6 4 1 5 7 0 4 6 9 1 3 2 5 8); array n[1] /nosymbols; k=length(s); call dynamic_array(n, k); do i=1 to k; n[i]=input(char(s,k-i+1),1.); end; c=0; do i=1 to k; c=d[c+1,p[mod(i-1,8)+1,n[i]+1]+1]; end; val=(c=0); return(val); endsub; run; options cmplib=work.funcs; /* Example */ data _null_; if vcdval('2363') then put 'Check digit is correct.'; else put 'Check digit is wrong.'; run;
Having the two functions in place, it's easy to check their consistency on, say, one million random digit strings with lengths ranging from 1 to, e.g., 40:
358 data _null_; 359 call streaminit('MT64',27182818); 360 length s $40; 361 do i=1 to 1e6; 362 s=' '; 363 do j=1 to rand('integer',40); 364 substr(s,j,1)=put(rand('integer',0,9),1.); 365 end; 366 if vcdval(cats(s,vcd(s)))=0 then do; 367 put 'ER' 'ROR: Wrong check digit encountered for ' s=; 368 stop; 369 end; 370 end; 371 run; NOTE: DATA statement used (Total process time): real time 20.93 seconds cpu time 20.79 seconds
Save $250 on SAS Innovate and get a free advance copy of the new SAS For Dummies book! Use the code "SASforDummies" to register. Don't miss out, May 6-9, in Orlando, Florida.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.