我想用Python从文本中提取IBAN号码。挑战在于,IBAN本身可以以如此多种方式编写,数字之间带有空格,以至于我觉得很难将其转换为有用的正则表达式模式。
我已经编写了一个演示版本,尝试从文本中匹配所有德国和奥地利的IBAN号码。
^DE([0-9a-zA-Z]\s?){20}$
我在stackoverflow看到了类似的问题。然而,不同的IBAN号码书写方式以及从文本中提取这些号码的方法的组合,使得解决我的问题变得非常困难。
希望你能帮我解决这个问题!
我想用Python从文本中提取IBAN号码。挑战在于,IBAN本身可以以如此多种方式编写,数字之间带有空格,以至于我觉得很难将其转换为有用的正则表达式模式。
我已经编写了一个演示版本,尝试从文本中匹配所有德国和奥地利的IBAN号码。
^DE([0-9a-zA-Z]\s?){20}$
ISO 语言代码 | 验证 # | 银行 # | 账户 # | |
---|---|---|---|---|
德国 | 2a | 2n | 8n | 10n |
奥地利 | 2a | 2n | 5n | 11n |
注意: a - 字母(仅限字母), n - 数字(仅限数字)
因此,主要的区别实际上在于数字的长度。这意味着您可以尝试:
\b(?:DE(?:\s*\d){20}|AT(?:\s*\d){18})\b(?!\s*\d)
查看在线演示。
\b
- 单词边界。(?:
- 打开第1个不捕获组。
DE
- 精确匹配大写的 "DE"。(?:
- 打开第2个不捕获组。
\s*\d
- 零个或多个空格,最多一个数字。){20}
- 关闭第2个不捕获组,并重复匹配20次。|
- 或:AT
- 精确匹配大写的 "AT"。(?:
- 打开第3个不捕获组。
\s*\d
- 零个或多个空格,最多一个数字。){18}
- 关闭第3个不捕获组,并重复匹配18次。)
- 关闭第1个不捕获组。\b
- 单词边界。(?!\s*\d)
- 负向前瞻,防止任何尾随的数字。它表明你的奥地利IBAN号码无效。如果你希望提取到它们仍然有效的点,我想你可以移除\b(?!\s*\d)
。
codes = re.findall(r'\b(DE(?:\s*[0-9]){20}|AT(?:\s*[0-9]){18})\b(?!\s*[0-9])', text)
详细信息:
\b
- 单词边界(DE(?:\s*[0-9]){20}|AT(?:\s*[0-9]){18})
- 第一组: DE
和 20 个数字的重复,之间可以有任意数量的空格,或者AT
,然后是 18 个单个数字的重复,最终用任意数量的空格分隔\b(?!\s*[0-9])
- 不是紧接着零个或多个空白符和 ASCII 数字的单词边界。请参见 此正则表达式演示。
对于您在问题中显示的包含非正确 IBAN 码的数据,您可以使用
\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}
- 十八个可选的空格和字母数字字符(?:(?:\s?[0-9a-zA-Z]){2})?
- 两个可选的序列,每个序列包含一个可选的空格和一个字母数字字符\b
- 单词边界。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
如果IBAN在字符串中 ==> (?<=(?i)IBAN.)CH\w{19} 如果IBAN不在字符串中 ==> CH\w{19}
\b(?:DE|AT)(?:\s?[0-9a-zA-Z]){20}\b
?请参见https://regex101.com/r/PRDDaT/2 - Wiktor Stribiżew\b(?:DE|AT)(?:\s?[0-9a-zA-Z]){18}(?:(?:\s?[0-9a-zA-Z]){2})?\b
。 - Wiktor Stribiżew