# Verifying a South African ID

I'm verifying South African IDs with jQuery, the code below works but Id like to know if it could be simplified in anyway or if there is a better way of doing things here?

South African IDs are verified as follows:

``````Using ID Number 8001015009087 as an example:
Add all the digits in the odd positions (excluding last digit).
8 + 0 + 0 + 5 + 0 + 0 = 13  .............................[1]

Move the even positions into a field and multiply the number by 2.
011098 x 2 = 22196  .....................................[2]

Add the digits of the result in [2].
2 + 2 + 1 + 9 + 6 = 20  .................................[3]

13 + 20 = 33  ...........................................[4]

Subtract the second digit of [4](i.e. 3) from 10. The number must tally with
the last number in the ID Number. If the result is 2 digits, the last digit is
used to compare against the last number in the ID Number. If the answer differs,
the ID number is invalid.
``````

And the code:

``````var me = \$("#id");
var odd = new Number();
var even_string = new String();
var even_result = new Number();
var even = new Number();
var result = new Number();

// Check length
if( me.val().length == 13 )
{
\$.each(me.val(), function(p,v){
if (p%2 == 0 & p != 12)
{
odd += Number(v); // --> 1. Add all odd positions except the last one.
}
else
{
if(p != 12)
{
even_string += String(v); // --> 2.1 Join all even positions.
}
}
});

// 2.2 Multiply even string by two.
even_result = (even_string * 2);

// 3. Add the digits of the new even result in two point two.
\$.each(String(even_result), function(p,v){
even += Number(v);
});

result = odd+even;

// 5. Subtract the second digit from step 4. from ten.
result = 10 - Number(String(result).substr(1,1));

// 6. Make sure we use the very last digit on the result.
if( (String(result)).length > 1 )
{
result = Number( (String(result)).charAt( (String(result)).length-1 ) );
}

// 6. The final check
if( Number(result) != me.val().substr(12,1) )
{
// Not a valid South African ID
}
};
``````
-
You can beautify (better indenting and spacing) or uglify (compress) it, I don't see why make changes to a fully working code which is as simple as that though. –  Fabrício Matté Jun 19 '12 at 14:13
First, read on the differences between `==` and `===`. Second, remove all of the `==` and `!=` you are using that needs no type conversion. –  rlemon Jun 19 '12 at 14:24
You also can avoid your dependance to jQuery by using `document.getElementById` `element.value` and `for`. –  dievardump Jun 19 '12 at 14:27
Are all ID numbers's the same length? –  Mark At Ramp51 Jun 19 '12 at 14:29
Also when you say sum the digits in odd positions for step 1, the index goes from the right to the left correct? So the second digit from the right would be index 0? Which is why the third digit from the right "0" is index 1 and is included as part of component 1? Correct? –  Mark At Ramp51 Jun 19 '12 at 14:33

## migrated from stackoverflow.comJun 19 '12 at 14:18

This question came from our site for professional and enthusiast programmers.

• jQuery is entirely unnecessary and will just make your solution slower
• Don't initialize to `new Class()` - this is not Java. Instead, initialize to the initial value, or `undefined` (`var x;`).
• use a function to encapsulate your verification logic, and to separate it from the DOM interface.
• don't call `me.val()` more than once; cache the result
• instead of the slow `\$.each`, use a simpler loop
• You already know the length of the id string, so you can get rid of the `p%2` check and simply operate twice on each loop, once on the current position and once on p + 1, and increment by 2 each time (this also results in half as many iterations, speeding up the loop even further).
• Cast using `+string` (resulting in a number) and `'' + number` (resulting in a string)
• split the string into the first 12 and the last 1 at the beginning, so you don't have to keep excluding the last character and re-extracting it.
• `'string'.slice(-1)` is a more concise way to access the last character in a string
• check to make sure that not only is the string 13 characters long, but also that every character is a numeral

With all that and a few stylistic preferences, here's my take on your problem:

``````function isValidSAID(id) {
var i, c,
even = '',
sum = 0,
check = id.slice(-1);

if (id.length != 13 || id.match(/\D/)) {
return false;
}
id = id.substr(0, id.length - 1);
for (i = 0; c = id.charAt(i); i += 2) {
sum += +c;
even += id.charAt(i + 1);
}
even = '' + even * 2;
for (i = 0; c = even.charAt(i); i++) {
sum += +c;
}
sum = 10 - ('' + sum).charAt(1);
return ('' + sum).slice(-1) == check;
}

if (!isValidSAID(document.getElementById('id').innerHTML)) {
}
``````
-
IE bug, use: check = id.slice(-1); –  Derrick Sep 10 '12 at 11:48
@Derrick thanks. You'd think I would know to always check IE by now. Answer fixed. –  st-boost Sep 12 '12 at 2:46

I don't know if it's simpler or more readable, it's kind of in the eye of the beholder. the immediate algorithm is more succinct. However it's still a little convoluted.

You can decide for yourself, but here is a different way of writing it.

http://jsfiddle.net/BJhSp/1/

-
• Instead of using `Number(v)`, use `+v`. This coerces a number out of v. Similarly, to get a string I would .toString() instead of `new String(v)`;

• I would also choose initialize numbers to `0`, and strings to `""` - or not initialize at all.

I like that you keep your algorithm simple, rather than condensing it.
Here is how I would refactor it:

``````// Wrapped in a self-executing function, not to polute the global scope.
(function (isNan, \$, console) {
"use strict";
function validateId(id) {
var odd_checksum = 0,
even_digits = "",
even_intermediate,
even_checksum = 0,
result = 0,
lastDigit;

// Check length
if (id.length !== 13) {
return false;
}

lastDigit = +id.charAt(12);
if (isNan(lastDigit)) {
return false;
}

\$.each(id, function (i, digit) {
if (i === 12) {
return false; // end
}
if (i % 2 === 0) {
odd_checksum += +digit; // --> 1. Add all odd positions except the last one.
} else {
even_digits += digit.toString(); // --> 2.1 Join all even positions.
}
});

// 2.2 Multiply even string by two.
even_intermediate = 2 * +even_digits;

// 3. Add the digits of the new even result in two point two.
\$.each(even_intermediate.toString(), function (i, digit) {
even_checksum += +digit;
});

result = odd_checksum + even_checksum;
// If there was any char not a digit, we have NaN here. ( i + NaN === NaN)
if (isNaN(result)) {
return false;
}

// 5. Subtract the second digit from step 4. from ten.
result = result.toString();
if (result.length > 1) {
result = +result.charAt(1);
} else {
result = 0;
}
result = 10 - result;

// 6. Make sure we use the very last digit on the result.
if (result === 10) {
result = 0;
}

// 6. The final check
if (result !== lastDigit) {
return false;
}

return true; // success!
}

// Testing.
var test_ids = [
"8001015009087",
"8001015009080"
],
test;
// Seems to work.
for (test in test_ids) {
test = test_ids[test];
if (validateId(test)) {
console.log("Your South African ID is valid:" + test);
} else {
console.log("Your South African ID is NOT valid:" + test);
}
}
} (isNaN, \$, window.console || { log: function (msg) { alert(msg); } }));
``````
-