计算ISIN校验和

时间:2017-09-05 18:27:32

标签: checksum

我知道这里可能有人对此提出疑问,但我找不到足够详细的答案,Wikipedia有两个ISIN示例,以及如何计算校验和。

我正在努力的计算部分是

  

将包含最右边字符的组相乘

我理解这句话的方式是:

  • 从右到左遍历每个角色
  • 一旦你偶然发现一个角色而不是数字记录它的位置
    • 如果该位置是even数字,则even位置
    • 中的所有数值加倍
    • 如果该位置是odd数字,则odd位置
    • 中的所有数值加倍

我的理解一定是错的,因为至少有两个问题:

  • 每个ISIN都以两个字符国家/地区代码开头,因此最右侧字符的位置始终是第一个字符
  • 如果省略前两个字符,则无法解释如何处理由所有数字组成的ISIN(前两个字符除外)

注意

isin.org包含有关验证ISIN的更少信息,它们甚至使用与维基百科相同的示例。

1 个答案:

答案 0 :(得分:0)

我同意你的观点,维基百科上的定义并不是我见过的最清晰的。

在两个示例之前有一段文字,当应该使用一个或另一个算法时,它会放弃。引用:

  

由于NSIN元素可以是任何字母数字序列(9个字符),因此奇数个字母将产生偶数个数字,偶数个字母将产生奇数个数字。对于奇数个数字,使用第一个示例中的方法。对于偶数位数,使用第二个示例中的方法

因此,如果您要验证US0378331005的校验和数字,您必须使用"第一算法"因为ISIN中有2个字母。 相反,如果您想检查AU0000XVGZA3,您将使用"第二种算法"因为ISIN包含7个字母。

关于"第一"和"第二"算法,它们是相同的,唯一的例外是在前者中你将2乘以奇数位组,而在后者中你将乘以2偶数位组。 / p>

现在,好消息是,如果没有这种过于复杂的算法,你就可以逃脱。

你可以改为:

  1. 取最后一位数字(您要确认)
  2. 以外的ISIN
  3. 将所有字母转换为数字,以获取数字列表
  4. 反转数字列表
  5. 如果结果为> = 10
  6. ,则奇数位置的所有数字都会加倍,并且它们的数字会再次相加
  7. 偶数位置的所有数字均为
  8. 对所有数字求和,取模数,从0减去结果并取绝对值
  9. 唯一棘手的步骤是#4。让我们用一个小例子来澄清它。 假设奇数位的数字是4, 0, 7

    你将他们加倍并获得:8, 0, 14

    8不是> = 10,所以我们照原样。同上为0. 14是> = 0,所以我们再次对其数字求和:1+4=5

    此迷你示例中步骤#4的结果是:8, 0, 5

    Python中最小的工作实现可能如下所示:

    import string
    
    def digit_sum(n):
        return (n // 10) + (n % 10)
    
    alphabet = {letter: value for (value, letter) in
                enumerate(''.join(str(n) for n in range(10)) + string.uppercase)}
    
    isin_to_digits = ''.join(str(d) for d in (alphabet[v] for v in isin[:-1]))
    isin_sum = 0
    for (i, c) in enumerate(reversed(isin_to_digits), 1):
        if i % 2 == 1:
            isin_sum += digit_sum(2*int(c))
        else:
            isin_sum += int(c)
    
    checksum_digit = abs(- isin_sum % 10)
    
    assert int(isin[-1]) == checksum_digit
    

    或者,更多的是为了功能性的乐趣而挤满了:

    checksum_digit = abs( - sum(digit_sum(2*int(c)) if i % 2 == 1 else int(c)
        for (i, c) in enumerate(
        reversed(''.join(str(d) for d in (alphabet[v] for v in isin[:-1]))), 1)) % 10)