12

我正在尝试解析来自我的(德国)银行的交易信函。我想从以下字符串中提取所有数字,结果比我想象的要难。选项 2 几乎可以满足我的要求。我现在想修改它以捕获例如 80。

我的第一次尝试是选项 1,它只返回垃圾。为什么它返回这么多空字符串?它应该总是至少有一个来自第一个 \d+ 的数字,不是吗?

选项 3 有效(或至少按预期工作),所以我以某种方式回答了我自己的问题。我想我主要是在思考为什么选项 2 不起作用。

# -*- coding: utf-8 -*-
import re


my_str = """
Dividendengutschrift für inländische Wertpapiere

Depotinhaber    : ME

Extag           :  18.04.2013          Bruttodividende
Zahlungstag     :  18.04.2013          pro Stück       :       0,9800 EUR
Valuta          :  18.04.2013

                                       Bruttodividende :        78,40 EUR
                                      *Einbeh. Steuer  :        20,67 EUR
                                       Nettodividende  :        78,40 EUR

                                       Endbetrag       :        57,73 EUR
"""

print re.findall(r'\d+(,\d+)?', my_str)
print re.findall(r'\d+,\d+', my_str)
print re.findall(r'[-+]?\d*,\d+|\d+', my_str)

输出是

['', '', '', '', '', '', ',98', '', '', '', '', ',40', ',67', ',40', ',73']
['0,9800', '78,40', '20,67', '78,40', '57,73']
['18', '04', '2013', '18', '04', '2013', '0,9800', '18', '04', '2013', '78,40', '20,67', '78,40', '57,73']
4

7 回答 7

12

选项 1 是最合适的正则表达式,但它无法正常工作,因为findall将返回捕获组匹配的内容(),而不是完整的匹配。

例如,您的示例中的前三个匹配项将是18,042013, 并且在每种情况下,捕获组都将不匹配,因此将向结果列表添加一个空字符串。

解决方案是使组不捕获

r'\d+(?:,\d+)?'

选项 2 仅在它不匹配不包含逗号的序列时才起作用。

选项 3 不是很好,因为它会匹配 eg +,1

于 2013-05-01T15:33:25.813 回答
9

我想从以下字符串中提取所有数字...

通过“数字”,如果您指的是货币金额和日期,我认为这将满足您的要求:

print re.findall(r'[0-9][0-9,.]+', my_str)

输出:

['18.04.2013', '18.04.2013', '0,9800', '18.04.2013', '78,40', '20,67', '78,40', '57,73']

如果“数字”仅指货币金额,则使用

print re.findall(r'[0-9]+,[0-9]+', my_str)

或者也许更好,

print re.findall(r'[0-9]+,[0-9]+ EUR', my_str)
于 2013-05-01T15:35:56.273 回答
2

这是一个解决方案,它解析语句并将结果放入一个名为的字典中bank_statement

# -*- coding: utf-8 -*-
import itertools

my_str = """
Dividendengutschrift für inländische Wertpapiere

Depotinhaber    : ME

Extag           :  18.04.2013          Bruttodividende
Zahlungstag     :  18.04.2013          pro Stück       :       0,9800 EUR
Valuta          :  18.04.2013

                                       Bruttodividende :        78,40 EUR
                                      *Einbeh. Steuer  :        20,67 EUR
                                       Nettodividende  :        78,40 EUR

                                       Endbetrag       :        57,73 EUR
"""

bank_statement = {}

for line in my_str.split('\n'):
    tokens = line.split()
    #print tokens


    it = iter(tokens)
    category = ''
    for token in it:
        if token == ':':
            category = category.strip(' *')
            bank_statement[category] = next(it)
            category = ''
        else:
            category += ' ' + token

# bank_statement now has all the values
print '\n'.join('{0:.<18} {1}'.format(k, v) \
                for k, v in sorted(bank_statement.items()))

此代码的输出:

Bruttodividende... 78,40  
Depotinhaber...... ME  
Einbeh. Steuer.... 20,67  
Endbetrag......... 57,73  
Extag............. 18.04.2013  
Nettodividende.... 78,40  
Valuta............ 18.04.2013  
Zahlungstag....... 18.04.2013  
pro Stück........ 0,9800  

讨论

  • 代码逐行扫描语句字符串
  • 然后它将每一行分成标记
  • 扫描令牌并查找冒号。如果找到,则将冒号之前的部分用作类别,将冒号之后的部分用作值。bank_statement['Extag']例如,值为“ 18.04.2013”
  • 请注意,所有的值都是字符串,而不是数字,但转换它们很琐碎。
于 2013-05-01T16:07:03.360 回答
1

这个问题是相关的;以下

print re.findall(r'\d+(?:,\d+)?', my_str)
                       ^^     

输出

['18', '04', '2013', '18', '04', '2013', '0,9800', '18', '04', '2013', '78,40', '20,67', '78,40', '57,73']

排除“点”数字有点复杂:

print re.findall(r'(?<!\d\.)\b\d+(?:,\d+)?\b(?!\.\d)', my_str)
                   ^^^^^^^^^^^            ^^^^^^^^^^

这输出

['0,9800', '78,40', '20,67', '78,40', '57,73']
于 2013-05-01T15:29:37.907 回答
0

试试这个:

re.findall(r'\d+(?:[\d,.]*\d)', my_str)

此正则表达式要求匹配至少以数字开头,然后是任意数量的数字、逗号和句点的混合,然后它也应该以数字结尾。

于 2013-05-01T15:37:17.987 回答
0

选项 2 与 '18.04.2013' 之类的数字不匹配,因为您匹配的是 '\d+,\d+' 这意味着

数字(一个或多个)逗号数字(一个或多个)

对于在您的情况下解析数字,我将使用

\s(\d+[^\s]+)

这转化为

space (get digit [one or more] get everything != space)

space = \s
get digit = \d
one or more = + (so it becomes \d+)
get everything != space = [^\s]
one or more = + (so it becomes [^\s]+
于 2013-05-01T15:37:35.573 回答
0

我没有非捕获组的解决方案

re.findall(r'(?<!\.)\b\d+[,\d]*\d\b(?!\.)', my_str)

  1. (?<!\.)- 检查任何数字之前是否没有.。(为了避免在日期 18.04.2013 中出现“2013”​​)

  2. \b\d+- 数字应该是单词字符串的开头

  3. [,\d]*- 考虑逗号或数字

  4. \d\b- number 应该是单词字符串的结尾

  5. (?!\.)- 检查任何数字后是否没有.。(为了避免在日期 18.04.2013 中出现“18”或“04”)

于 2021-10-08T06:00:34.960 回答