使用 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) - DEAT (?:\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)从文本中提取城市时出错

在 Python 中使用 BeautifulSoup 从脚本标签中提取文本

无法使用地理位置从文本中提取城市名称(Python)

在python中使用PDFMiner从PDF文件中提取文本?

如何使用python从图像中提取文本或数字

python 使用BeautifulSoup和Python从网页中提取文本