Module:Check ISIN

-- Module to check ISIN numbers. -- Example usage: --  -- Console example: --  mw.log(p.check({isin="IE00B4L5Y983"}))

require('Module:No globals')

local p = {} local arguments = require('Module:Arguments')

-- https://en.wikipedia.org/wiki/ISO_3166-1 -- https://www.isin.org/isin/ local _countries = { A = "DEFGILMOQRSTUWXZ", B = "ABDEFGHIJLMNOQRSTVWYZ", C = "ACDFGHIKLMNORUVWXYZ", D = "EJKMOZ", E = "CEGHRST", F = "IJKMOR", G = "ABDEFGHILMNPQRSTUWY", H = "KMNRTU", I = "DELMNOQRST", J = "EMOP", K = "EGHIMNPRWYZ", L = "ABCIKRSTUVY", M = "ACDEFGHKLMNOPQRSTUVWXYZ", N = "ACEFGILOPRUZ", O = "M", P = "AEFGHKLMNRSTWY", Q = "A", R = "EOSUW", S = "ABCDEGHIJKLMNORSTVXYZ", T = "CDFGHJKLMNORTVWZ", U = "AGMSYZ", V = "ACEGINU", W = "FS", X = "" .. "S", Y = "ET", Z = "AMW", }

local function _is_country(isin) return _countries[isin:sub(1, 1)]:find(isin:sub(2, 2)) end

-- https://en.wikipedia.org/wiki/International_Securities_Identification_Number#Examples -- Letter mapping is base-36: A->10 to Z->35 local function _make_numeric(isin) local numeric = "" for c in isin:gmatch(".") do numeric = numeric .. tostring(tonumber(c, 36)) end return numeric end

-- https://en.wikipedia.org/wiki/Luhn_algorithm local function _check_luhn(string_) local rev, sum = string_:reverse, 0 for i = 1, rev:len do		local digit = ((i % 2) == 0 and 2 or 1) * tonumber(rev:sub(i, i)) sum = sum + digit - (digit > 9 and 9 or 0) end return (sum % 10) == 0 end

local function _check_isin(isin) isin = isin:upper if isin:len == 12 and isin:match("^[A-Z][A-Z][A-Z%d]+%d$") and _is_country(isin) then return _check_luhn(_make_numeric(isin)) end return false end

function p._countries local letters, countries = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "" for c1 in letters:gmatch(".") do		for c2 in letters:gmatch(".") do local code = c1 .. c2 countries = countries .. (_is_country(code) and code .. ", " or "") end end return countries:sub(1, -3) end

function p.countries return p._countries end

function p._check(args) local isin = args["isin"] or args[1] or "" if _check_isin(isin) then return args["valid"] or args[2] or "valid" else return args["invalid"] or args[3] or "invalid" end end

function p.check(frame) local args = arguments.getArgs(frame, {trim = false, removeBlanks = false}) return p._check(args) end

return p