使用Python从文本中提取IBAN

6

我想用Python从文本中提取IBAN号码。挑战在于,IBAN本身可以以如此多种方式编写,数字之间带有空格,以至于我觉得很难将其转换为有用的正则表达式模式。

我已经编写了一个演示版本,尝试从文本中匹配所有德国和奥地利的IBAN号码。

^DE([0-9a-zA-Z]\s?){20}$

我在stackoverflow看到了类似的问题。然而,不同的IBAN号码书写方式以及从文本中提取这些号码的方法的组合,使得解决我的问题变得非常困难。
希望你能帮我解决这个问题!

1
\b(?:DE|AT)(?:\s?[0-9a-zA-Z]){20}\b?请参见https://regex101.com/r/PRDDaT/2 - Wiktor Stribiżew
哇,这看起来像是完美的匹配!太棒了! - PParker
3
德国的IBAN号码有22个字符,奥地利的则有20个字符。因此您不能将它们视为相同的处理。 - JvdV
1
有趣的是,看起来正确,所以应该是\b(?:DE|AT)(?:\s?[0-9a-zA-Z]){18}(?:(?:\s?[0-9a-zA-Z]){2})?\b - Wiktor Stribiżew
4个回答

4
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)


1
一般来说,为了匹配德国和奥地利的IBAN代码,您可以使用
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) - DEAT
  • (?:\s?[0-9a-zA-Z]){18} - 十八个可选的空格和字母数字字符
  • (?:(?:\s?[0-9a-zA-Z]){2})? - 两个可选的序列,每个序列包含一个可选的空格和一个字母数字字符
  • \b - 单词边界。

3
友情提示,IBAN号码只能包含ISO代码之后的数字。您可能会出现误报,包括超过18位数字的奥地利IBAN号码。 - JvdV
1
@JvdV 谢谢,已经注意到了。然而,我认为 OP 的数据中并没有纯粹的 IBAN 号码,因此正确的 IBAN 详细信息可能不相关。 - Wiktor Stribiżew

0
假设您正在使用此验证程序,并将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

0

如果IBAN在字符串中 ==> (?<=(?i)IBAN.)CH\w{19} 如果IBAN不在字符串中 ==> CH\w{19}


我怀疑这是错误的Python解决方案语法。请尝试https://stackoverflow.com/editing-help。 - Yunnosch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接