Python正则表达式(正则表达式)匹配逗号分隔数 - 为什么这不起作用?

时间:2013-05-01 15:20:41

标签: python regex

我正在尝试解析我(德国)银行的交易信件。 我想从以下字符串中提取所有数字,结果证明比我想象的更难。 选项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']

6 个答案:

答案 0 :(得分:10)

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

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

解决方案是使群组无法捕捉

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

选项2不起作用,因为它不匹配不包含逗号的序列。

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

答案 1 :(得分:5)

  

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

按“数字”,如果你的意思是货币金额和日期,我认为这会做你想要的:

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)

答案 2 :(得分: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'
  • 请注意,所有值都是字符串,而不是数字,但转换它们是琐事。

答案 3 :(得分:1)

This question是相关的;以下

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

OUPUTS

['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']

答案 4 :(得分:0)

试试这个:

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

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

答案 5 :(得分: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]+