ISIN Validation with Javascript

Posted on 12 Feb 2011

As part of a recent integration project, I found that I needed to use ISIN codes as a common key. ISINs are an internationally recognised way of labelling exchange listed securities. As with many things my first call for an overview was wikipedia, although investopedia and the motley fool are fantastic sites for finding out more about finance industry concepts.

While the wikipedia article was great, I was disappointed to find the link to the javascript validator was dead. Given that the input end of this particular project is built in ExtJS, this meant it was back to the drawing board. So, in the spirit of giving back, here is a simple javascript implementation of an ISIN validator.

/**
 * @author sellistonball
 */

/**
 * Calculates a check digit for an isin
 * @param {String} code an ISIN code with country code, but without check digit
 * @return {Integer} The check digit for this code
 */
function calcISINCheck(code) {
    var conv = '';
    var digits = '';
    var sd = 0;
    // convert letters
    for(var i =0; i < code.length; i++) {
        var c = code.charCodeAt(i);
        conv += (c > 57) ? (c - 55).toString() : code[i]
    }
    // group by odd and even, multiply digits from group containing rightmost character by 2
    for (var i = 0 ; i < conv.length; i++) {
        digits += (parseInt(conv[i])*((i % 2)==(conv.length % 2 != 0 ? 0 : 1) ? 2 : 1)).toString();
    }
    // sum all digits
    for (var i = 0; i< digits.length; i++) {
        sd += parseInt(digits[i]);
    }
    // subtract mod 10 of the sum from 10, return mod 10 of result 
    return (10 - (sd % 10)) % 10;
}
function isValidISIN(isin){
    // basic pattern
    var regex = /^(BE|BM|FR|BG|VE|DK|HR|DE|JP|HU|HK|JO|BR|XS|FI|GR|IS|RU|LB|PT|NO|TW|UA|TR|LK|LV|LU|TH|NL|PK|PH|RO|EG|PL|AA|CH|CN|CL|EE|CA|IR|IT|ZA|CZ|CY|AR|AU|AT|IN|CS|CR|IE|ID|ES|PE|TN|PA|SG|IL|US|MX|SK|KR|SI|KW|MY|MO|SE|GB|GG|KY|JE|VG|NG|SA|MU)([0-9A-Z]{9})([0-9])$/;
    var match = regex.exec(isin);
    if (match.length != 4) return false;
    // validate the check digit
    return (match[3] == calcISINCheck(match[1] + match[2]));
}

Known caveats include that I have not 100% checked all the country codes, and they may need the odd one or two added, but the mod 10 algorithm is thoroughly tested. I have included a few simple test cases here.

function testValidIsins() {
    assertTrue(isValidISIN('US0378331005');
}

function testInvalidCountry() {
    assertFalse(isValidISIN('ZZ0378331005');
}

function testInvalidCheckDigit() {
    assertFalse(isValidISIN('US0378331001');
    assertFalse(isValidISIN('US0378331002');
    assertFalse(isValidISIN('US0378331003');
    assertFalse(isValidISIN('US0378331004');
    assertFalse(isValidISIN('US0378331006');
    assertFalse(isValidISIN('US0378331007');
    assertFalse(isValidISIN('US0378331008');
    assertFalse(isValidISIN('US0378331009');
}

These tests rely on the JSUnit library, which is great for this sort of quick test when you don't really need something as heavy as selenium.

For those of you using the excellent ExtJS library, here is a vtype definition of the validator two, and an example text field configured to input ISINs.

Ext.form.VTypes.isin = isValidISIN;
Ext.form.VTypes.isinText = 'Invalid ISIN';

Yes, it's that simple. I hope all this is useful to someone.

StackOverflow Flair

profile for Simon Elliston Ball at Stack Overflow, Q&A for professional and enthusiast programmers