我编写了一个简单的Python验证器,我希望对它进行一些评论。
引用维基百科的话,我们知道:
国际银行帐号(IBAN)是一种国际商定的跨国界银行账户识别系统,以便利跨境交易的沟通和处理,减少抄写错误的风险。
现在,IBAN可能如下所示: GB82WEST12345698765432
有三种算法可以验证IBAN:
在我的程序中,我只使用了前两个方法。
描述(来自维基):
通过将IBAN转换为整数并对其执行基本的mod-97操作(如ISO 7064所述),将对IBAN进行验证。如果IBAN有效,余数等于1。IBAN验证算法如下:检查IBAN总长度是否正确。否则,IBAN将四个初始字符移动到字符串的末尾,用两位数替换字符串中的每个字母,从而扩展字符串,其中A= 10,B= 11,…,Z= 35,将字符串解释为十进制整数,并在除以97上计算该数字的余数,如果余数为1,则通过检查数字测试,IBAN可能有效。示例(虚构的联合王国银行,排序代码为12-34-56,帐号98765432):·IBAN: GB82WEST12345698765432·重排: WEST12345698765432GB82·转换为整数: 3214282912345698765432161182·计算余数:3214282912123456986432161182 mod 97 =1
描述(来自维基):
根据ECBS“IBAN的生成应由为帐户服务的银行/分行的专属责任”。8文件复制了部分ISO/IEC 7064:2003标准,作为在02至98范围内生成支票数字的一种方法。检查范围为00至96、01至97和03至99的数字也将提供IBAN的验证,但标准中没有提到是否可以使用这些范围。首选的算法是:
letter_dic = {"A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16, "H": 17, "I": 18, "J": 19, "K": 20,
"L": 21, "M": 22, "N": 23, "O": 24, "P": 25, "Q": 26, "R": 27, "S": 28, "T": 29, "U": 30, "V": 31,
"W": 32, "X": 33, "Y": 34, "Z": 35,
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9}
letters = {ord(k): str(v) for k, v in letter_dic.items()}
def chech_validation_chars_iban(iban):
zeros_iban = iban[:2] + '00' + iban[4:]
iban_inverted = zeros_iban[4:] + zeros_iban[:4]
iban_numbered = iban_inverted.translate(letters)
verification_chars = 98 - (int(iban_numbered) % 97)
if verification_chars < 10:
verification_chars = '{:02}'.format(int(verification_chars))
return verification_chars
def validate_iban(iban):
iban_inverted = iban[4:] + iban[:4]
iban_numbered = iban_inverted.translate(letters)
return int(iban_numbered) % 97
if __name__ == '__main__':
my_iban = 'RO13RZBR0000060007134800'
if chech_validation_chars_iban(my_iban) == int(my_iban[2:4]):
if validate_iban(my_iban) == 1:
print('IBAN ok!\n')
else:
print('IBAN nok!\n')
else:
print('IBAN nok!\n')
任何可能出错的建议、提示或改进都是欢迎的!
发布于 2016-07-20 00:36:25
我会做的改变,从上到下:
string
和enumerate
来制作字典。而不是手工制作。letters
是一个常量,所以使用LETTERS
。chech_validation_chars_iban
重命名为名称generate_iban_check_digits
,因为它不是检查,而是转换。{:0>2}
和删除if。validate_iban
以检查它是否有效,因此返回一个布尔值。and
可以减少ifs的数量。这导致:
import string
LETTERS = {ord(d): str(i) for i, d in enumerate(string.digits + string.ascii_uppercase)}
def _number_iban(iban):
return (iban[4:] + iban[:4]).translate(LETTERS)
def generate_iban_check_digits(iban):
number_iban = _number_iban(iban[:2] + '00' + iban[4:])
return '{:0>2}'.format(98 - (int(number_iban) % 97))
def valid_iban(iban):
return int(_number_iban(iban)) % 97 == 1
if __name__ == '__main__':
my_iban = 'RO13RZBR0000060007134800'
if generate_iban_check_digits(my_iban) == my_iban[2:4] and valid_iban(my_iban):
print('IBAN ok!\n')
else:
print('IBAN not ok!\n')
这有一个合并问题,规范指出它既允许大写输入,也允许小写输入:
用数字替换字符串中的字母,必要时展开字符串,使A或a= 10,B或b= 11,Z或z= 35。因此,每个字母字符替换为2位数字。
然而,我们只允许大写。为了修改这一点,我会更改字母dict,使之包括小写字母。但这使得代码读起来有点困难,而不是那么干净。因此,最干净的方法可能是使用itertools.chain
,使用我们现在使用的方法。
_LETTERS = chain(enumerate(string.digits + string.ascii_uppercase),
enumerate(string.ascii_lowercase, 10))
LETTERS = {ord(d): str(i) for i, d in _LETTERS}
发布于 2019-06-02 01:48:19
您可以使用regex和lambda函数简化字母到数字的转换:
re.sub('[A-Z]', lambda m: str(ord(m.group()) - 55), (iban[4:] + iban[:4]))
翻译用一个数字的AFAIK替换字符。因此,可能不是这个IBAN用例的最佳选择。
https://codereview.stackexchange.com/questions/135366
复制