You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中去除重叠号码范围中的重复项?

号码范围去重展开问题与解决方案

问题描述

我有一个包含号码范围的列表,需要将每个范围展开为单个号码并关联对应标签(country、region、PBX,存在则保留),要求无重复项,出现重复时保留最小范围的标签。例如重叠范围976431[000-799]、9764317[00-99]、97643179[0-9],应处理为976431[000-699]、9764317[00-89]、97643179[0-9]以避免重复。但当前使用的Python脚本会生成重复项(如号码976431799出现三次),原脚本代码如下:

import numpy as np

MYRANGES = [
    {'Name': 'list1', 'Prefix': '976431[000-799]', 'Tag': 'Country=cz;Region=eu;'},
    {'Name': 'list2', 'Prefix': '9764317[00-99]', 'Tag': 'Country=cz;Region=eu;Pbx=freepbx;'},
    {'Name': 'list3', 'Prefix': '97643179[0-9]', 'Tag': 'Country=cz;Region=eu;Pbx=asterisk;'},
]

def ddi2csv(myranges):

    for myrange in myranges:
        prefixrange = myrange['Prefix'].replace(']', '').split('[')[0]
        suffixrange = myrange['Prefix'].replace(']', '').split('[')[1].split('-')

        for digit in np.arange(int(suffixrange[0]),
                               int(suffixrange[1]) + 1):
            suffix = f"{digit:{str(0) + str(len(suffixrange[0]))}}"
            print(
                str(myrange['Name'].lower()) + "_" + str(suffix),
                prefixrange + suffix,
                myrange['Tag']
                      )

ddi2csv(MYRANGES)

解决思路与修改后代码

核心逻辑是先处理范围重叠冲突,保留最具体(长度最长)的范围标签,再展开号码,从根源避免重复生成。具体步骤:

  1. 将所有范围解析为完整的数字区间(起始、结束号码),同时保留标签、前缀等信息
  2. 按号码总长度从长到短排序,长度越长的范围优先级越高(越具体)
  3. 用高优先级范围切割低优先级范围,移除重叠部分
  4. 对处理后的无重叠范围进行展开输出

修改后的代码:

def parse_range(prefix_str):
    # 解析前缀字符串为完整的起始、结束数字,以及后缀长度、前缀
    prefix, suffix_part = prefix_str.replace(']', '').split('[')
    start_suffix, end_suffix = suffix_part.split('-')
    suffix_len = len(start_suffix)
    start_num = int(f"{prefix}{start_suffix}")
    end_num = int(f"{prefix}{end_suffix}")
    return start_num, end_num, suffix_len, prefix

def resolve_overlaps(ranges):
    # 解析所有范围为统一格式的区间对象
    parsed_ranges = []
    for item in ranges:
        start, end, suffix_len, prefix = parse_range(item['Prefix'])
        parsed_ranges.append({
            'start': start,
            'end': end,
            'tag': item['Tag'],
            'name': item['Name'],
            'suffix_len': suffix_len,
            'prefix': prefix
        })
    
    # 按号码总长度降序排序,优先保留更具体的范围
    parsed_ranges.sort(key=lambda x: len(str(x['start'])), reverse=True)
    
    resolved = []
    for current in parsed_ranges:
        curr_start = current['start']
        curr_end = current['end']
        # 检查当前范围与已保留范围的重叠,切割出不重叠部分
        for existing in resolved.copy():
            # 当前范围完全被现有范围包含,直接跳过
            if curr_start >= existing['start'] and curr_end <= existing['end']:
                curr_start = None
                break
            # 部分重叠,切割当前范围
            elif curr_start <= existing['end'] and curr_end >= existing['start']:
                if curr_start < existing['start']:
                    # 保留当前范围的前半段不重叠部分
                    resolved.append({
                        'start': curr_start,
                        'end': existing['start'] - 1,
                        'tag': current['tag'],
                        'name': current['name'],
                        'suffix_len': current['suffix_len'],
                        'prefix': current['prefix']
                    })
                curr_start = existing['end'] + 1
                if curr_start > curr_end:
                    break
        # 若还有剩余不重叠部分,加入结果列表
        if curr_start is not None and curr_start <= curr_end:
            resolved.append({
                'start': curr_start,
                'end': curr_end,
                'tag': current['tag'],
                'name': current['name'],
                'suffix_len': current['suffix_len'],
                'prefix': current['prefix']
            })
    # 按起始号码升序排序,方便输出顺序更合理
    resolved.sort(key=lambda x: x['start'])
    return resolved

def ddi2csv(myranges):
    resolved_ranges = resolve_overlaps(myranges)
    for rng in resolved_ranges:
        # 生成后缀的格式化字符串,确保补零到指定长度
        suffix_format = f"0{rng['suffix_len']}d"
        for num in range(rng['start'], rng['end'] + 1):
            # 提取后缀部分并格式化
            suffix = str(num)[len(rng['prefix']):]
            suffix = format(int(suffix), suffix_format)
            print(
                f"{rng['name'].lower()}_{suffix}",
                f"{rng['prefix']}{suffix}",
                rng['tag']
            )

# 测试数据
MYRANGES = [
    {'Name': 'list1', 'Prefix': '976431[000-799]', 'Tag': 'Country=cz;Region=eu;'},
    {'Name': 'list2', 'Prefix': '9764317[00-99]', 'Tag': 'Country=cz;Region=eu;Pbx=freepbx;'},
    {'Name': 'list3', 'Prefix': '97643179[0-9]', 'Tag': 'Country=cz;Region=eu;Pbx=asterisk;'},
]

ddi2csv(MYRANGES)

代码说明

  • parse_range:将带范围的前缀字符串转换为可计算的数字区间,为后续重叠处理打基础
  • resolve_overlaps:核心去重逻辑,通过优先级排序和范围切割,确保每个号码只属于最具体的范围
  • ddi2csv:对处理后的无重叠范围进行展开,输出符合要求的号码、名称后缀和标签

内容的提问来源于stack exchange,提问作者user7478971

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 16:48:26