Исправить номер телефона по шаблону regexp на python

Появилась потребность исправлять номер телефона по регулярному выражению. на вход подают номер телефона (например +79991112233) и маску к которой надо привести номер:

mask="^(\\d{10})$" надо получить 9991112233

mask="^\\((\\d{3})\\)(\\d{3})\\-(\\d{2})\\-(\\d{2})$" надо получить (999)111-22-33

номер который дают привожу к 10 цифрам так:

phone = [digit for digit in phone_number if digit.isdigit()][1:]

а как дальше из этого сделать номер по переданной маске?

Как посоветовал @Алексей Р, сделал универсальную входную маску и пытаюсь сгенерировать выходную по маске, получилось как-то очень костыльно:

mask = "+7(<!^\\d{0,3}$>)<!^\\d{0,3}$>-<!^\\d{0,2}$>-<!^\\d{0,2}$>"
# mask = "+7<!^\\d{0,10}$>"
phone = "9991112233"

res = []
start = r"<!^\d{0,"
end = r"}$>"
skip = 0
replace = False
group = 1
for i, st in enumerate(mask):
    if mask.find(start, i, i + len(start)) != -1:
        skip = len(start)
        replace = True
    if mask.find(end, i, i + len(end)) != -1:
        skip = len(end)
    if skip > 0:
        skip -= 1
        continue
    if replace:
        for _ in range(int(mask[i: mask.find(end, i)])):
            res.append(f"\\{group}")
            group += 1
        replace = False
        skip = 1
     else:
        res.append(st)

out_mask = "".join(res)

result = re.sub(r"(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)", out_mask, phone)
print(result)

Мне это не очень нравится, может можно как-то более красиво переписать?


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

Автор решения: Алексей Р

Вариант, когда входной формат в точности не определен, но он является корректным, если содержит 11 цифр.

import re

numbers = ('+7 (999) 1-1-1-2233', '+7/ 999 /888 /77/ 66', '-51254', '+7123457894455214', '+79991234567')
in_mask = r'(\d)' * 10
out_masks = (r'(\1\2\3)\4\5\6-\7\8-\9\10', r'\1\2\3\4\5\6\7\8\9\10', r'+7 \1\2\3 \4\5\6\7-\8\9\10')

for n in numbers:
    phone = ''.join([digit for digit in n if digit.isdigit()][1:])
    if len(phone) == 10:
        for m in out_masks:
            print(re.sub(in_mask, m, phone))
    else:
        print(f'Номер {n} не соответствует входной маске')
(999)111-22-33
9991112233
+7 999 1112-233
(999)888-77-66
9998887766
+7 999 8887-766
Номер -51254 не соответствует входной маске
Номер +7123457894455214 не соответствует входной маске
(999)123-45-67
9991234567
+7 999 1234-567
→ Ссылка
Автор решения: vskarpushin

решил следующим способом, правим номер телефона под маску которую нам дали:

import re


def tel_format(phone, mask):
    block_reg_exp = "<!.*?>"
    while True:
        found_block = re.search(block_reg_exp, mask)
        if found_block is None:
            break
        block = found_block.group(0)
        temporary_mask = "#" * int(re.search(r",\d+", block).group(0)[1:])
        mask = mask.replace(found_block.group(0), temporary_mask)

    phone = [digit for digit in phone if digit.isdigit()][1:]
    phone_mask = list(mask)
    for i, elem in enumerate(phone_mask):
        if elem == "#":
            phone_mask[i] = phone.pop(0)
    return "".join(phone_mask)


assert tel_format("79998887766", "(<!^\\d{0,3}$>)<!^\\d{0,3}$>-<!^\\d{0,2}$>-<!^\\d{0,2}$>") == "(999)888-77-66"
assert tel_format("79998887766", "+7(<!^\\d{0,3}$>)<!^\\d{0,7}$>") == "+7(999)8887766"
assert tel_format("79998887766", "<!^\\d{0,10}$>") == "9998887766"
assert tel_format("79998887766", "+7-<!^\\d{0,3}$>-<!^\\d{0,3}$>-<!^\\d{0,2}$>-<!^\\d{0,2}$>") == "+7-999-888-77-66"
assert tel_format("+7-999-888-77-66", "(<!^\\d{0,3}$>)<!^\\d{0,3}$>-<!^\\d{0,1}$>-<!^\\d{0,1}$>-<!^\\d{0,1}$>-<!^\\d{0,1}$>") == "(999)888-7-7-6-6"
assert tel_format("+7(999)888-77-66", "+7<!^\\d{0,10}$>") == "+79998887766"
assert tel_format("+7(999)8887766", "<!^\\d{0,10}$>") == "9998887766"
→ Ссылка