使用 Python 从文本中提取 IBAN

Extract IBAN from text with Python

我想从 Python 的文本中提取 IBAN 号码。这里的挑战是,IBAN 本身可以用数字之间的空格以多种方式编写,我发现很难将其转换为有用的正则表达式模式。

我写了一个 demo version 试图从文本中匹配所有德国和奥地利的 IBAN 号码。

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

我在Whosebug上看到过类似的问题。但是,结合使用不同的方式来编写 IBAN 号码以及从文本中提取这些号码,这​​让我的问题很难解决。

希望你能帮助我!

一般来说,要匹配德国和奥地利的 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}) - 第 1 组:DE 和 20 次重复的数字,中间有任意数量的空格,或者 AT 然后 18 次重复的单个数字,最终用任何空格分隔空格数量
  • \b(?!\s*[0-9]) - 没有紧跟零个或多个空格和一个 ASCII 数字的字边界。

参见 this regex demo

对于您在问题中显示的包含非正确 IBAN 代码的数据,您可以使用

\b(?:DE|AT)(?:\s?[0-9a-zA-Z]){18}(?:(?:\s?[0-9a-zA-Z]){2})?\b

regex demo详情:

  • \b - 单词边界
  • (?:DE|AT) - DEAT
  • (?:\s?[0-9a-zA-Z]){18} - 出现 18 次可选空格,然后是字母数字字符
  • (?:(?:\s?[0-9a-zA-Z]){2})? - 可选空格和字母数字字符的两个序列的可选出现
  • \b - 单词边界。
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} - 关闭第二个非捕获组并匹配它 20 次。
    • | - 或者:
    • AT - 按字面匹配大写“AT”。
    • (?:- 打开第三个非捕获组。
      • \s*\d - 零个或多个空格,最多一位数。
      • ){18} - 关闭第二个非捕获组并匹配它 20 次。
    • ) - 关闭第一个非捕获组。
  • \b - 字边界。
  • (?!\s*\d) - 否定前瞻以防止任何尾随数字。

确实表明您的奥地利 IBAN 号码无效。如果您想提取到它们仍然有效的程度,我想您可以删除 \b(?!\s*\d)

假设您在 class 中使用此验证并将 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