An International Securities Identification Number (ISIN) is a unique international identifier for a financial security such as a stock or bond.



Task

Write a function or program that takes a string as input, and checks whether it is a valid ISIN.

It is only valid if it has the correct format,   and   the embedded checksum is correct.

Demonstrate that your code passes the test-cases listed below.



Details

The format of an ISIN is as follows:


┌───────────── a 2-character ISO country code (A-Z)
│ ┌─────────── a 9-character security code (A-Z, 0-9)
│ │        ┌── a checksum digit (0-9)
AU0000XVGZA3



For this task, you may assume that any 2-character alphabetic sequence is a valid country code.

The checksum can be validated as follows:

 Replace letters with digits, by converting each character from base 36 to base 10, e.g. AU0000XVGZA3 →1030000033311635103.
 Perform the Luhn test on this base-10 number.
There is a separate task for this test: Luhn test of credit card numbers.
You don't have to replicate the implementation of this test here   ───   you can just call the existing function from that task.   (Add a comment stating if you did this.)


Test cases



 ISIN

 Validity

 Comment


 US0378331005 
 valid 



 US0373831005 
 not valid 
 The transposition typo is caught by the checksum constraint.


 U50378331005 
 not valid 
 The substitution typo is caught by the format constraint.


 US03378331005 
 not valid 
 The duplication typo is caught by the format constraint.


 AU0000XVGZA3 
 valid 



 AU0000VXGZA3 
 valid 
 Unfortunately, not all transposition typos are caught by the checksum constraint.


 FR0000988040 
 valid 


(The comments are just informational.   Your function should simply return a Boolean result.   See #Raku for a reference solution.)



Related task:

 Luhn test of credit card numbers


Also see

 Interactive online ISIN validator
 Wikipedia article: International Securities Identification Number


 
CREATE FUNCTION dbo._ISINCheck( @strISIN VarChar(40) )
RETURNS bit
AS
BEGIN
--*** Test an ISIN code and return 1 if it is valid, 0 if invalid.
DECLARE @bValid	 bit;
 
SET @bValid = CASE WHEN @strISIN LIKE '[A-Z][A-Z][A-Z,0-9][A-Z,0-9][A-Z,0-9][A-Z,0-9][A-Z,0-9][A-Z,0-9][A-Z,0-9][A-Z,0-9][A-Z,0-9][0-9]' THEN 1 ELSE 0 END
IF @bValid = 1
	BEGIN
		DECLARE @strTest VarChar(40) = '';
		DECLARE @strAdd  VarChar(2);
		DECLARE @p INT = 0;
		WHILE @p < LEN(@strISIN)
			BEGIN
				SET @p = @p+1;
				SET @strAdd = SUBSTRING(@strISIN,@p,1);
				IF @strAdd LIKE '[A-Z]' SET @strAdd = CONVERT(VarChar(2),ASCII(UPPER(@strAdd))-55);
				SET @strTest = @strTest + @strAdd;
			END;
 
		-- Proceed with Luhn test
		DECLARE @strLuhn VarChar(40) = REVERSE(@strTest); -- usage: set once, never changed
		DECLARE @strS2Values VarChar(10) = '0246813579';  -- constant: maps digits to their S2 summed values
		SET @p = 0; -- reset loop counter
		DECLARE @intValue INT;
		DECLARE @intSum	INT = 0;
		-- loop through the reversed string, get the value (even-positioned digits are mapped) and add it to @intSum
		WHILE @p < LEN(@strLuhn)
			BEGIN
				SET @p = @p+1;
				SET @intValue = CONVERT(INT, SUBSTRING(@strLuhn,@p,1) ) -- value of the digit at position @p in the string
				IF @p % 2 = 0	SET @intValue = CONVERT(INT,SUBSTRING(@strS2Values,@intValue+1,1))
				SET @intSum = @intSum + @intValue
			END
		-- If the of the digits' mapped values ends in 0 (modulo 10 = 0) then the Luhn test succeeds
		SET @bValid = CASE WHEN @intSum % 10 = 0 THEN 1 ELSE 0 END 
	END;
 
RETURN @bValid
END
 