As part of an integration against a third party service I need to calculate a check digit. I have been given a PHP snippet to show the algorithm but I need to implement it in pl/sql. The PHP snippet (taken from here) is:
function arvutaViitenumber($nr){
$nr = (string)$nr;
$kaal = array(7,3,1);
$sl = $st = strlen($nr);
$total = 0;
while($sl > 0 and substr($nr, --$sl, 1) >='0'){
$total += substr($nr, ($st-1)-$sl, 1)*$kaal[($sl%3)];
}
$kontrollnr = ((ceil(($total/10))*10)-$total);
return $nr.$kontrollnr;
}
I understand most of it except the substr($nr, --$sl, 1) >='0'
condition in the loop. There are two things I do not understand about this:
The main body of the loop takes each digit in order from the start. Why then have a condition where the loop exits before processing the nth digit from the start based on the state of the nth digit from the end?
When comparing a single-character string as greater or equal string '0'
can the condition ever be false? In my tests it is always true, even if the string compared is a character not a number.
Question 1 is more of accademic intrest. My real interest is question 2 and how I will implement this check in the pl/sql version (or if I even need to?)
1. Well, think how the reverse would go.
$st = strlen($nr);
$sl = $total = 0;
while($sl < strlen($nr) and substr($nr, ++$sl, 1) >='0'){
Notice the strlen
in the while loop - bad practice. Although in PHP it's fast, in most programming languages this is horrible for performance. The alternative would be to use another variable, which would be reduntant.
So the best option for both lazyness and performance is to start from the end.
2. As far as I can tell, the only purpose of that string comparison is to make sure the position in the ASCII table is higher or equal to '0'
ASCII no. 48). First, check the http://www.asciitable.com/
Then take a look at the following tests I did:
var_dump(' ' >= '0'); // false // space has ASCII no 32
var_dump('(' >= '0'); // false // ASCII no 47
var_dump('A' >= '0'); // true // ASCII no 65
var_dump('[' >= '0'); // true // ASCII no 71
So it's almost an alphanumeric test, as @mudasobwa mentioned.
When comparing a single-character string as greater or equal string '0' can the condition ever be false? In my tests it is always true, even if the string compared is a character not a number.
"<string>" >= '0'
is false, if <string>
is either empty or null or negative number, but true if 0 or '0' or other
Dont be fooled by the types here, >=
will (in contrast to >==
) default to / cast to some type. (and since its php, its impossible to remember which, at least for me)
Edit: also false >= '0'
is true - this might be intended here
1. You should not try to find any logic in the algorhytm here: it’s kinda hash function and it’s goal is to give the same “verifying” value on same input. Take a look at Java’s String::hashCode()
implementation, for instance.
2. They decide to bring an additional entropy by stopping a loop when the n-th from the end is not alphanumeric. Nothing more. There is no hidden sense.