Task: Validate International Securities Identification Number







Python: def check_isin(a):
    if len(a) != 12 or not all(c.isalpha() for c in a[:2]) or not all(c.isalnum() for c in a[2:]):
        return False
    s = "".join(str(int(c, 36)) for c in a)
    return 0 == (sum(sum(divmod(2 * (ord(c) - 48), 10)) for c in s[-2::-2]) +
                 sum(ord(c) - 48 for c in s[::-2])) % 10


def check_isin_alt(a):
    if len(a) != 12:
        return False
    s = []
    for i, c in enumerate(a):
        if c.isdigit():
            if i < 2:
                return False
            s.append(ord(c) - 48)
        elif c.isupper():
            if i == 11:
                return False
            s += divmod(ord(c) - 55, 10)
        else:
            return False
    v = sum(s[::-2])
    for k in s[-2::-2]:
        k = 2 * k
        v += k - 9 if k > 9 else k
    return v % 10 == 0

[check_isin(s) for s in ["US0378331005", "US0373831005", "U50378331005", "US03378331005",
                         "AU0000XVGZA3", "AU0000VXGZA3", "FR0000988040"]]







Ada: procedure ISIN is
   
   function Luhn_Test (Number: String) return Boolean is
      Sum  : Natural := 0;
      Odd  : Boolean := True;
      Digit: Natural range 0 .. 9;
   begin
      for p in reverse Number'Range loop
         Digit := Integer'Value (Number (p..p));
         if Odd then
            Sum := Sum + Digit;
         else
            Sum := Sum + (Digit*2 mod 10) + (Digit / 5);
         end if;
         Odd := not Odd;
      end loop;
      return (Sum mod 10) = 0;
   end Luhn_Test;
   
   subtype Decimal   is Character range '0' .. '9';
   subtype Letter    is Character range 'A' .. 'Z';
   subtype ISIN_Type is String(1..12);
   
   
   function To_Digits(S: String) return String is
      
      Offset: constant Integer := Character'Pos('A')-10;
   
      Invalid_Character: exception;
   begin
      if S = "" then
         return "";
      elsif S(S'First) = ' ' then 
         return To_Digits(S(S'First+1 .. S'Last)); 
      elsif S(S'First) in Decimal then 
         return S(S'First) & To_Digits(S(S'First+1 .. S'Last));
      elsif S(S'First) in Letter then
         return To_Digits(Integer'Image(Character'Pos(S(S'First))-Offset))
           & To_Digits(S(S'First+1 .. S'Last));
      else 
         raise Invalid_Character;
      end if;
   end To_Digits;
   
   function Is_Valid_ISIN(S: ISIN_Type) return Boolean is
      Number : String := To_Digits(S);
   begin
      return S(S'First)   in Letter  and
             S(S'First+1) in Letter  and
             S(S'Last)    in Decimal and
             Luhn_Test(Number);
   end Is_Valid_ISIN;

   Test_Cases : constant Array(1..6) of ISIN_Type :=
      ("US0378331005",
       "US0373831005",
       "U50378331005",
       
       
       "AU0000XVGZA3",
       "AU0000VXGZA3",
       "FR0000988040");
begin
   for I in Test_Cases'Range loop
      Ada.Text_IO.Put_Line(Test_Cases(I) & ":" &
        Boolean'Image(Is_Valid_ISIN(Test_Cases(I))));
   end loop;
   
   Ada.Text_IO.Put("US03378331005:");
   Ada.Text_IO.Put_Line(Boolean'Image(Is_Valid_Isin("US03378331005")));
exception
   when others =>
      Ada.Text_IO.Put_Line("Exception occured");
end ISIN;