Python. Преобразование диапазонов чисел в список строк с маской

Прошу помощи сообщества в написании скрипта на python для решения следующией на первый взгляд не сложной задачи. Имеется входны данные диапазонов номеров телефонов и их принадлежности к часовой зоне - порядка 8000 строк. Пример значений:

От, До, Часовая зона

9000000000,9000000999,GMT+03:00

9010001000,9000002999,GMT+05:00

Необходимо на выходе получить набор строковых значений вида:

9000000XXX,GMT+03:00

9010001XXX,GMT+05:00

9010002XXX,GMT+05:00

Под такие ровные дапазоны скрипт получился очень простой и рабочий:

def getLength(value: int): # определяю количество разрядов, которые делятся на 10 без остатка
    count = 0
    while not value % 10:
        value //= 10
        count += 1
    return count

def createAndSend(lstFrom, lstTo, mask, timeZone, title): # Формирование строки по маске
    while lstFrom <= lstTo:
        code = (str(lstFrom)+mask)
        lstFrom += 1
        lstOut.append({"Шаблон номера телефона": code, "Часовой пояс": timeZone})
    return lstOut

for i in lstIn:
    elem1 = int(i[0]) # Первый номер диапазона
    elem2 = int(i[1]) # Последний номер диапазона
    timeZone = i[2] # Часовая зона
    qnty = elem2 - elem1 + 1 # Емкость. Можно сразу работать с диапазоном csv, но вдруг будет другая БД
    length = getLength(qnty) # Получаем количество разрядов, которое можно заменить маской "Х"

    if length == 1:
        mask=''
    elif length == 2:
        mask='X'
    elif length == 3:
        mask='XX'
    elif length == 4:
        mask='XXX'
    elif length == 5:
        mask='XXXX'
    elif length == 6:
        mask='XXXXX'
    elif length == 7:
        mask='XXXXXX'
    elif length == 8:
        mask='XXXXXXX'
    elif length == 9:
        mask='XXXXXXXX'

    lstFrom = elem1 // 10**(length-1)
    lstTo = elem2 // 10**(length-1)

    res = createAndSend(lstFrom, lstTo, mask, timeZone)

Проблемы начинаются когда встречаются резаные диапазоны, например начинаются с неровного числа или заканчиваются не кратно 10. Есть диапазоны, которые содержат 1 номер, 2 номера, 1234 номера и тп.

Есть вот такой диапазон для примера: 9410888290,9425504999,GMT+03:00

Основная цель - описать диапазон максимально коротким количеством строк по маске и конечно же не пропустить данные. С этим я зашел в тупик. Начал мудрить кучей проверок, даже показывать стыдно во что код начал превращаться:) Может изначально выбран неверный алгритм и можно все это упростить? В общем хотелось бы услышать дельных советов


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy
def ranges(low, high):
    assert len(low) == len(high)
    assert low <= high
    n = len(low)

    for i in range(n):
        if low[i] != high[i]:
            break
    else:
        i = n

    if low[i:] == '0' * (n - i) and high[i:] == '9' * (n - i):
        yield low[:i] + 'X' * (n - i)
        return

    assert low[i] < high[i]
    
    for r in ranges(low[i:], low[i] + '9' * (n - i - 1)):
        yield low[:i] + r

    for d in range(int(low[i]) + 1, int(high[i])):
        yield low[:i] + str(d) + 'X' * (n - i - 1)

    for r in ranges(high[i] + '0' * (n - i - 1), high[i:]):
        yield low[:i] + r


for r in ranges(*input().split()):
    print(r)
$ echo 9410888290 9425504999 | python ranges.py
941088829X
94108883XX
94108884XX
94108885XX
94108886XX
94108887XX
94108888XX
94108889XX
9410889XXX
941089XXXX
94109XXXXX
9411XXXXXX
9412XXXXXX
9413XXXXXX
9414XXXXXX
9415XXXXXX
9416XXXXXX
9417XXXXXX
9418XXXXXX
9419XXXXXX
9420XXXXXX
9421XXXXXX
9422XXXXXX
9423XXXXXX
9424XXXXXX
94250XXXXX
94251XXXXX
94252XXXXX
94253XXXXX
94254XXXXX
9425500XXX
9425501XXX
9425502XXX
9425503XXX
9425504XXX
→ Ссылка