我想用 Python 从文本中提取 IBAN 号码。这里的挑战是,IBAN 本身可以以多种方式编写,数字之间有空格,我发现很难将其翻译成有用的正则表达式模式。
我编写了一个演示版本,它试图匹配文本中的所有德国和奥地利 IBAN 号码。
^DE([0-9a-zA-Z]\s?){20}$
我在stackoverflow上看到过类似的问题。然而,编写 IBAN 数字的不同方法的组合以及从文本中提取这些数字,使得解决我的问题变得非常困难。
希望你能帮助我!
我想用 Python 从文本中提取 IBAN 号码。这里的挑战是,IBAN 本身可以以多种方式编写,数字之间有空格,我发现很难将其翻译成有用的正则表达式模式。
我编写了一个演示版本,它试图匹配文本中的所有德国和奥地利 IBAN 号码。
^DE([0-9a-zA-Z]\s?){20}$
我在stackoverflow上看到过类似的问题。然而,编写 IBAN 数字的不同方法的组合以及从文本中提取这些数字,使得解决我的问题变得非常困难。
希望你能帮助我!
ISO地码 | 确认# | 银行# | 帐户# | |
---|---|---|---|---|
德国 | 2a | 2n | 8n | 10n |
奥地利 | 2a | 2n | 5n | 11n |
注意: a - 字母(仅限字母),n - 数字(仅限数字)
所以主要区别实际上是数字的长度。这意味着您可以尝试:
\b(?:DE(?:\s*\d){20}|AT(?:\s*\d){18})\b(?!\s*\d)
请参阅在线演示。
\b
- 字边界。(?:
- 打开第一个非捕获组。
DE
- 从字面上匹配大写“DE”。(?:
- 打开第二个非捕获组。
\s*\d
- 零个或多个空格,最多一位数。){20}
- 关闭第2个非捕获组并匹配20次。|
- 或者:AT
- 从字面上匹配大写“AT”。(?:
- 打开第三个非捕获组。
\s*\d
- 零个或多个空格,最多一位数。){18}
- 关闭第2个非捕获组并匹配20次。)
- 关闭第一个非捕获组。\b
- 字边界。(?!\s*\d)
- 负前瞻以防止任何尾随数字。它确实表明您的奥地利 IBAN 号码无效。如果您希望提取到它们仍然有效的程度,我想您可以删除\b(?!\s*\d)
您可以使用
\b(?:DE|AT)(?:\s?[0-9a-zA-Z]){18}(?:(?:\s?[0-9a-zA-Z]){2})?\b
请参阅正则表达式演示。详情:
\b
- 单词边界(?:DE|AT)
-DE
或AT
(?:\s?[0-9a-zA-Z]){18}
- 出现 18 次可选空格,然后是字母数字字符(?:(?:\s?[0-9a-zA-Z]){2})?
- 两个序列的可选空格和字母数字字符的可选出现\b
- 单词边界。假设您在以 self.input 作为输入字符串的类中使用此验证,请使用以下代码。虽然如果您只想验证德国和奥地利的 IBAN,我建议您从字典中删除所有其他国家:
country_dic = {
"AL": [28, "Albania"],
"AD": [24, "Andorra"],
"AT": [20, "Austria"],
"BE": [16, "Belgium"],
"BA": [20, "Bosnia"],
"BG": [22, "Bulgaria"],
"HR": [21, "Croatia"],
"CY": [28, "Cyprus"],
"CZ": [24, "Czech Republic"],
"DK": [18, "Denmark"],
"EE": [20, "Estonia"],
"FO": [18, "Faroe Islands"],
"FI": [18, "Finland"],
"FR": [27, "France"],
"DE": [22, "Germany"],
"GI": [23, "Gibraltar"],
"GR": [27, "Greece"],
"GL": [18, "Greenland"],
"HU": [28, "Hungary"],
"IS": [26, "Iceland"],
"IE": [22, "Ireland"],
"IL": [23, "Israel"],
"IT": [27, "Italy"],
"LV": [21, "Latvia"],
"LI": [21, "Liechtenstein"],
"LT": [20, "Lithuania"],
"LU": [20, "Luxembourg"],
"MK": [19, "Macedonia"],
"MT": [31, "Malta"],
"MU": [30, "Mauritius"],
"MC": [27, "Monaco"],
"ME": [22, "Montenegro"],
"NL": [18, "Netherlands"],
"NO": [15, "Northern Ireland"],
"PO": [28, "Poland"],
"PT": [25, "Portugal"],
"RO": [24, "Romania"],
"SM": [27, "San Marino"],
"SA": [24, "Saudi Arabia"],
"RS": [22, "Serbia"],
"SK": [24, "Slovakia"],
"SI": [19, "Slovenia"],
"ES": [24, "Spain"],
"SE": [24, "Sweden"],
"CH": [21, "Switzerland"],
"TR": [26, "Turkey"],
"TN": [24, "Tunisia"],
"GB": [22, "United Kingdom"]
} # dictionary with IBAN-length per country-code
def eval_iban(self):
# Evaluates how many IBAN's are found in the input string
try:
if self.input:
hits = 0
for word in self.input.upper().split():
iban = word.strip()
letter_dic = {ord(d): str(i) for i, d in enumerate(
string.digits + string.ascii_uppercase)} # Matches letter to number for 97-proof method
correct_length = country_dic[iban[:2]]
if len(iban) == correct_length[0]: # checks whether country-code matches IBAN-length
if int((iban[4:] + iban[:4]).translate(letter_dic)) % 97 == 1:
# checks whether converted letters to numbers result in 1 when divided by 97
# this validates the IBAN
hits += 1
return hits
return 0
except KeyError:
return 0
except Exception:
# logging.exception('Could not evaluate IBAN')
return 0