使用 Python 从文本中提取 IBAN
Posted
技术标签:
【中文标题】使用 Python 从文本中提取 IBAN【英文标题】:Extract IBAN from text with Python 【发布时间】:2021-04-20 10:05:07 【问题描述】:我想用 Python 从文本中提取 IBAN 数字。这里的挑战是,IBAN 本身可以以多种方式编写,数字之间有空格,我发现很难将其转换为有用的正则表达式模式。
我写了一个demo version,它试图从文本中匹配所有德国和奥地利的 IBAN 号码。
^DE([0-9a-zA-Z]\s?)20$
我在 *** 上看到过类似的问题。然而,编写 IBAN 数字的不同方式以及从文本中提取这些数字的不同方式的组合,使得解决我的问题变得非常困难。
希望你能帮助我!
【问题讨论】:
\b(?:DE|AT)(?:\s?[0-9a-zA-Z])20\b
?见regex101.com/r/PRDDaT/2
哇,这看起来很完美!太棒了!
德语 IBAN
数字是 22 个字符,奥地利是 20。所以你不能把它们一视同仁。
有意思,貌似that's correct,所以应该是\b(?:DE|AT)(?:\s?[0-9a-zA-Z])18(?:(?:\s?[0-9a-zA-Z])2)?\b
【参考方案1】:
假设您在以 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
【讨论】:
【参考方案2】:ISO landcode | Verification# | Bank# | Account# | |
---|---|---|---|---|
Germany | 2a | 2n | 8n | 10n |
Austria | 2a | 2n | 5n | 11n |
注意:a - 字母(仅限字母),n - 数字(仅限数字)
所以主要区别实际上是数字的长度。这意味着您可以尝试:
\b(?:DE(?:\s*\d)20|AT(?:\s*\d)18)\b(?!\s*\d)
见在线demo。
\b
- 字边界。
(?:
- 打开第一个非捕获组。
DE
- 从字面上匹配大写“DE”。
(?:
- 打开第二个非捕获组。
\s*\d
- 零个或多个空格,最多一个数字。
)20
- 关闭第 2 个非捕获组并匹配 20 次。
|
- 或者:
AT
- 从字面上匹配大写“AT”。
(?:
- 打开第三个非捕获组。
\s*\d
- 零个或多个空格,最多一个数字。
)18
- 关闭第 2 个非捕获组并匹配 20 次。
)
- 关闭第一个非捕获组。
\b
- 字边界。
(?!\s*\d)
- 负前瞻以防止出现任何尾随数字。
这确实表明您的奥地利 IBAN 号码无效。如果您希望提取到它们仍然有效的程度,我想您可以删除\b(?!\s*\d)
【讨论】:
【参考方案3】:你可以使用
\b(?:DE|AT)(?:\s?[0-9a-zA-Z])18(?:(?:\s?[0-9a-zA-Z])2)?\b
请参阅regex demo。 详情:
\b
- 字边界
(?:DE|AT)
- DE
或 AT
(?:\s?[0-9a-zA-Z])18
- 出现 18 次可选空格,然后是字母数字字符
(?:(?:\s?[0-9a-zA-Z])2)?
- 两个序列的可选出现可选空格和字母数字字符
\b
- 字边界。
【讨论】:
只是一个友好的提示,但 IBAN 号码只能包含从 ISO 代码开始的号码。您可能会在此处返回误报,包括超过 18 位的奥地利 IBAN 号码。 @JvdV 谢谢,注意到了。但是,在我看来,OP 的数据中没有纯 IBAN 号码,因此正确的 IBAN 详细信息可能不相关。以上是关于使用 Python 从文本中提取 IBAN的主要内容,如果未能解决你的问题,请参考以下文章
在 Python 中使用 BeautifulSoup 从脚本标签中提取文本