如何从正则表达式匹配中获取索引?

时间:2016-02-11 00:12:30

标签: python regex functional-programming

我正在为我的问题寻找更多的pythonic或函数式编程解决方案。

我将regular expression与字符串匹配。正则表达式捕获每个重复的通配符周围的组。我使用这些组来掩盖匹配中的通配符。以下代码中显示了一个示例:

out_str_list = []
original_str = 'XYZQUACKESTARNFSDMADESBHSCHILDABCD'
match = re.search('(?=(QUACK(.{2,4})TAR(.{2,4})MAD(.{3,5})CHILD))', original_str)   # searching while grouping repetitions of wildcards
hide_ranges = tuple(match.span(i) for i in range(2, len(match.groups()) + 1))   # ((8, 10), (13, 17), (20, 25))
match_range = match.span(1) # (3, 30)
i = 0

out_str_list.append(original_str[match.span(1)[0]:hide_ranges[0][0]])
while i < len(hide_ranges):
    out_str_list.append("-({0})-".format(hide_ranges[i][1] - hide_ranges[i][0]))
    if i == 0 and len(hide_ranges) != 1:
        out_str_list.append(original_str[hide_ranges[0][1]:hide_ranges[1][0]])
    elif i == len(hide_ranges) - 1:
        pass
    else:
        out_str_list.append(original_str[hide_ranges[i][1]:hide_ranges[i+1][0]])
    i += 1
out_str_list.append(original_str[hide_ranges[i-1][1]:match.span(1)[1]])
match_str = ''.join(out_str_list)

assert match_str = 'QUACK-(2)-TAR-(4)-MAD-(5)-CHILD'

代码有效,但似乎比需要的更冗长。此示例的更一般形式:

我有一个字符串:XYZQUACKESTARNFSDMADESBHSCHILDABCD

从正则表达式匹配中,我生成元组:((8, 10), (13, 17), (20, 25))

以及包含匹配的起始和结束索引的元组:(3, 30)

如何获得如下字符串:QUACK-(2)-TAR-(4)-MAD-(5)-CHILD

我想为每个捕获的组执行类似str.splitstr.join({length of gap})的操作。我无法做到这一点,因为我给了索引而不是字符串来分割。我知道函数式编程方法会使用map或filter之类的东西,但我不确定如何以我想要的方式应用字符串切片。

2 个答案:

答案 0 :(得分:4)

您可以使用re.split提取字符串的不匹配部分,并使用re.findall查找字符串的匹配部分。然后,您可以遍历这些集合,并将数据聚合在一起:

import re

s = 'XYZQUACKESTARNFSDMADESBHSCHILDABCD'
matches = re.findall('QUACK|TAR|MAD|CHILD',s)
non_matches = re.split('QUACK|TAR|MAD|CHILD',s)
'-'.join(["{}-({})".format(matches[i], len(non_matches[i+1])) for i in range(len(matches))])
#'QUACK-(2)-TAR-(4)-MAD-(5)-CHILD-(4)'

答案 1 :(得分:1)

回想一下re.sub可以使用替换功能,所以你可以这样做:

>>> s='XYZQUACKESTARNFSDMADESBHSCHILDABCD'
>>> def mh(m):
...     return "{}-({})-{}-({})-{}-({})-{}".format(m.group(1),len(m.group(2)),m.group(3),len(m.group(4)),m.group(5),len(m.group(6)),m.group(7))
... 
>>> re.sub(r'^.*(QUACK)(.{2,4})(TAR)(.{2,4})(MAD)(.{3,5})(CHILD).*$', mh, s)
'QUACK-(2)-TAR-(4)-MAD-(5)-CHILD'

你也可以使用你的正则表达式替换Python的字符串:

>>> m=re.search(r'(?=(QUACK(.{2,4})TAR(.{2,4})MAD(.{3,5})CHILD))', s)
>>> tgt=m.groups()[0]
>>> for r1, r2 in [(e, '-({})-'.format(len(e))) for e in m.groups()[1:]]:
...    tgt=tgt.replace(r1, r2, 1)
... 
>>> tgt
'QUACK-(2)-TAR-(4)-MAD-(5)-CHILD'