【问题标题】:Python Regular expression of group to match text before amount组的Python正则表达式以匹配金额之前的文本
【发布时间】:2020-09-18 21:10:35
【问题描述】:

我正在尝试编写一个 python 正则表达式,它从数据框中的几列中捕获多个值。下面的正则表达式尝试做同样的事情。字符串有 4 个部分。

group 1: Date - month and day
group 2: Date - month and day
group 3: description text before amount i.e. group 4
group 4: amount  - this group is optional

第 3 组的一些特殊条件 - 文本 (1) 文本本身可能包含“-”、“$”等字符。所以我们不能使用 - & $ 作为文本的边界。 (2) 文本(第 3 组)有时后面可能没有数量。 (3) 第 3 组和第 4 组之间的空格是可选的

下面是python函数代码,它接收一个具有4列c1、c2、c3、c4的数据帧,在处理后将列dt、txt和amt添加到数据帧。

def parse_values(args):
    re_1='(([JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC]{3}\s{0,}[\d]{1,2})\s{0,}){2}(.*[\s]|.*[^\$]|.*[^-]){1}([-+]?\$[\d|,]+(?:\.\d+)?)?'
    srch=re.search(re_1, args[0])
    if srch is None:
        return args
    m = re.match(re_1, args[0])
    args['dt']=m.group(1)
    args['txt']=m.group(3)
    args['amt']=m.group(4)
    if m.group(4) is None:
        if pd.isnull(args['c3']):
            args['amt']=args.c2
        else:
            args['amt']=args.c3
    return args

为了测试结果,我有以下 6 行需要返回正确格式的 amt 列作为回报。

tt=[{'c1':'OCT 7 OCT 8 HURRY CURRY THORNHILL ','c2':'$16.84'},
        {'c1':'OCT 7 OCT 8 HURRY CURRY THORNHILL','c2':'$16.84'},
        {'c1':'MAR 15 MAR 16 LOBLAWS FOODS INC - EAST YORK -$80,00,7770.70'},
        {'c1':'MAR 15 MAR 16 LOBLAWS FOODS INC - EAST YORK-$2070.70'},
        {'c1':'MAR 15 MAR 16 LOBLAWS FOODS INC - EAST YORK$2070.70'},
        {'c1':'MAR 15 MAR 16 LOBLAWS FOODS INC - EAST YORK $80,00,7770.70'}
    ]
t=pd.DataFrame(tt,columns=['c1','c2','c3','c4'])
t=t.apply(parse_values,1)
t

但是,由于 re_1 中的正则表达式错误,我无法正确解析 amt 列和 txt 列,因为它们返回 NaN 或遗漏了一些单词(如下面输出图像的某些行所示)。

【问题讨论】:

  • 这可能不是解决方案,但我现在可能应该告诉你字符集 ([]) 不能那样工作。它们匹配整个集合中的单个字符[JAN] 将匹配来自 JAN 的 J, A, N,而 (JAN) 匹配整个 JAN 字符串

标签: python regex pandas dataframe


【解决方案1】:

这个怎么样:

(((?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\s*[\d]{1,2})\s*){2}(.*?)\s*(?=[\-$])([-+]?\$[\d|,]+(?:\.\d+)?)

regex101.com

所示

说明:

首先,我通过更改一些小细节来缩短正则表达式,例如使用\s* 而不是\s{0,},这意味着完全相同。

整个[Jan|...|DEC] 代码使用了一个字符类,即[],它只取整个集合中的一个字符。使用非捕获组是从多个字母的不同组中选择的正确方法,在您的情况下是“月”。

正则表达式的精髓:LOOKAHEADS

(?=[\-$]) 告诉正则表达式(.*) 中它前面的文本应该尽可能匹配,直到它找到一个后跟破折号或美元符号的位置。前瞻实际上并不匹配他们正在寻找的任何东西,它们只是告诉正则表达式前瞻的参数应该遵循那个位置。

【讨论】:

  • 前瞻表达式(?=[\-$])好像可以去掉了。
  • 感谢 Robo Mop 的回复。我相信我之前没有提到第 3 组的一些特殊条件 - 文本(1)文本本身可能包含诸如“-”、“$”之类的字符。所以我们不能使用 - & $ 作为文本的边界。 (2) 文本(第 3 组)有时后面可能没有数量。 (3) 第 3 组和第 4 组之间的空格是可选的,我将在原始问题中进行编辑。
猜你喜欢
  • 2011-03-12
  • 2019-03-21
  • 2017-12-16
  • 1970-01-01
  • 1970-01-01
  • 2014-03-14
  • 2013-07-25
  • 2022-11-23
  • 1970-01-01
相关资源
最近更新 更多