在正则表达式匹配项中合并间隔

Merging intervals in regex matches

提问人:Aurora Arctic 提问时间:2/14/2023 最后编辑:Aurora Arctic 更新时间:2/20/2023 访问量:66

问:

我试图使用 python 在文本中查找所有类型的参考资料,例如“附录 2”、“第 17 节”或“附表 12.2”。找到此类匹配项后的问题是其中一些重叠,我想将它们加入一个新字符串中,或者只考虑最长的字符串,删除子字符串。

为此,我创建了多个正则表达式模式,使代码更具可读性,然后将它们插入到列表中,对列表中的所有模式调用 finditer。 从匹配中,我收集文本和文本中的位置作为开始和结束索引。

def get_references(text):
    refs = [{
        'text': match.group(),
        'span': { 
            'start': match.span()[0],
            'end': match.span()[1]
    }} 
        for ref in references_regex for match in finditer(ref, text)]  

这意味着,尽管相同或变化不大(例如“本书第 17.4 节”和“本书第 17.4 节”和“本书第 17.4 节”和“本书第 17.4 节”),但仍会在结果中多次插入由多个模式匹配的引用。

我尝试将重叠模式与一些临时函数合并,但仍然无法正常工作。

您知道是否有办法删除重复项或合并它们以防它们重叠吗?

例如,我有:

[{"text": "Schedule 15.1", "span": {"start": 756, "end": 770}},
 {"text": "15.1 of the Framework Agreement", "span": {"start": 765, "end": 796}},
 {"text": "17.14 of the book", "span": {"start": 1883, "end": 1900}]

我想得到:

 {"text": "Schedule 15.1 of the Framework Agreement", "span": {"start": 756, "end": 796}},
 {"text": "17.14 of the book", "span": {"start": 1883, "end": 1900}]

先谢谢你!

python 重叠匹配

评论

0赞 Tranbi 2/14/2023
“我尝试将重叠的模式与一些临时函数合并,但仍然无法正常工作。” 你能详细说明一下吗?你尝试了什么?你的模式是什么?你在说什么功能?我认为将您的模式合并为一个模式可能是这里的关键......
0赞 Aurora Arctic 2/15/2023
我尝试创建一个函数,根据索引测试一个匹配项是否是另一个匹配项的子字符串。如果是这样,我们将合并它们并仅保存它们的合并。但是我在存储没有重复的匹配项时也遇到了问题,并且提供了多个版本的合并。

答:

1赞 Ted Nguyen 2/14/2023 #1

您的问题称为合并间隔。您可以在 leetcode 中签出问题并阅读解决方案部分。

你可以试试我的代码,这段代码实现了你的特定问题的解决方案。它可能有错误,因为我没有使用更大的数据集进行测试。

编辑:请注意,您的列表应按升序排序

def process(match_list):
    if not match_list:
        return []

    new_list = []
    new_text = match_list[0]['text']
    start, end = match_list[0]['span']['start'], match_list[0]['span']['end']

    for i in range(1, len(match_list)):
        # If overlap
        if end >= match_list[i]['span']['start']:
            # Merge the text and update the ending position
            new_text += match_list[i]['text'][end-match_list[i]['span']['start']-1:]
            end = max(end, match_list[i]['span']['end'])
        else:
            # If not overlap, append the text to the result
            new_list.append({'text': new_text, 'span': {'start': start, 'end': end}})
            # Process the next text
            new_text = match_list[i]['text']
            start, end = match_list[i]['span']['start'], match_list[i]['span']['end']

    # Append the last text in the list
    new_list.append({'text': new_text, 'span': {'start': start, 'end': end}})
    return new_list

评论

0赞 Aurora Arctic 2/15/2023
感谢您的建议!我确实尝试过类似的东西,但它提供了一些错误,因为某些解决方案会无缘无故地被删除或通过在结尾/开头添加多个字母来合并。我将尝试对其进行相应的修改,并在评论中发布解决方案。
0赞 Mazhar 2/14/2023 #2
def get_s_e(x):
    s, e = map(x['span'].get, ['start', 'end'])
    return s, e


def concat_dict(a):
    a = sorted(a, key=lambda x: x['span']['start'], reverse=True)

    index = 0
    while index < len(a):
        cur = a[index]
        try:
            nxt = a[index+1]
        except:
            break
        cur_st, cur_end = get_s_e(cur)
        nxt_st, nxt_end = get_s_e(nxt)

        if cur_st <= nxt_end:
            join_index = cur_st-nxt_st

            if nxt_end >= cur_end:
                text = nxt['text']
                a[index]['span']['end'] = nxt_end
            else:
                text = n['text'][:join_index]+cur['text']

            a[index]['text'] = text
            a[index]['span']['start'] = nxt_st

            del a[index+1]
        else:
            index += 1

    return a
a = [{"text": "Book bf dj Schedule 15.1 of the", "span": {"start": 745, "end": 776}},
     {"text": "Schedule 15.1", "span": {"start": 756, "end": 770}},
     {"text": "15.1 of the Framework Agreement", "span": {"start": 765, "end": 796}},
     {"text": "17.14 of the book", "span": {"start": 1883, "end": 1900}}
    ]
print(concat_dict(a))

输出:

[{'text': '17.14 of the book', 'span': {'start': 1883, 'end': 1900}},
 {'text': 'Book bf dj Book bf d15.1 of the Framework Agreement',
  'span': {'start': 745, 'end': 796}}]