Python: используйте регулярное выражение для сопоставления номера телефона и печати кортежа (с ограничениями форматирования)

Я хочу написать код, который может анализировать американские телефонные номера (т.е. (664)298-4397). Ниже приведены ограничения:

  • разрешить начальные и конечные пробелы
  • разрешать пробелы между кодом города и местными номерами
  • без пробелов в коде города или семизначном номере XXX-XXXX

В конечном итоге я хочу напечатать кортеж строк (area_code, first_three_digits_local, last_four_digits_local)

У меня два блока вопросов.

Вопрос 1. Ниже приведены входные данные, которые мой код должен принять и распечатать кортеж:

  • '(664) 298-4397', '(664)298-4397', ' (664) 298-4397'

Ниже приведен код, который я пробовал:

regex_parse1 = re.match(r'^([\s]*[(]*[0-9]*[)]*[\s]*)+([\s]*[0-9]*)-([0-9]*[\s]*)$', '(664) 298-4397')
print (f' groups are: {regex_parse1.groups()} \n')

regex_parse2 = re.match(r'^([\s]*[(]*[0-9]*[)]*[\s]*)+([\s]*[0-9]*)-([0-9]*[\s]*)$', '(664)298-4397')
print (f' groups are: {regex_parse2.groups()} \n')

regex_parse3 = re.match(r'^([\s]*[(]*[0-9]*[)]*[\s]*)+([\s]*[0-9]*)-([0-9]*[\s]*)$', '   (664)      298-4397')
print (f' groups are: {regex_parse3.groups()}')     

Строковый ввод для всех трех допустим и должен возвращать кортеж:

('664', '298', '4397')

Но вместо этого я получаю вывод ниже для всех трех:

groups are: ('', '', '4397')   

Что я делаю не так?

Вопрос 2. Следующие два фрагмента кода должны выводить объект «NoneType» без атрибута «группа», потому что введенная строка номера телефона нарушает ограничения. Но вместо этого я получаю результаты для всех трех.

regex_parse4 = re.match(r'^([\s]*[(]*[0-9]*[)]*[\s]*)+([\s]*[0-9]*)-([0-9]*[\s]*)$', '(404)555 -1212')
print (f' groups are: {regex_parse4.groups()}')

regex_parse5 = re.match(r'^([\s]*[(]*[0-9]*[)]*[\s]*)+([\s]*[0-9]*)-([0-9]*[\s]*)$', ' ( 404)121-2121')
print (f' groups are: {regex_parse5.groups()}')

Ожидаемый результат: должна быть ошибка, но вместо этого я получаю это для всех трех:

groups are: ('', '', '2121')

Что не так с моим кодом регулярного выражения?


person PineNuts0    schedule 19.02.2021    source источник


Ответы (2)


В общем, ваше регулярное выражение злоупотребляет звездочкой *. Детали следующим образом:

У вас есть 3 группы захвата:

  1. ([\s]*[(]*[0-9]*[)]*[\s]*)
  2. ([\s]*[0-9]*)
  3. ([0-9]*[\s]*)

Вы используете звездочку для каждого элемента, включая открывающую и закрывающую скобки. На самом деле почти все в вашем регулярном выражении выделено звездочкой. Таким образом, группы захвата также соответствуют пустым строкам. Вот почему ваши первая и вторая группы захвата возвращают пустые строки. Единственный элемент, который вы не используете звездочкой, — это знак дефиса - непосредственно перед третьей группой захвата. Это также причина, по которой ваше регулярное выражение может захватить третью группу захвата, как в 4397 и 2121

Чтобы решить вашу проблему, вы должны использовать звездочку только тогда, когда это необходимо.

На самом деле у вашего регулярного выражения еще много возможностей для улучшения. Например, теперь он соответствует числовым цифрам любой длины (вместо блоков из 3 или 4 цифр). Это также позволяет использовать код города, не заключенный в круглые скобки (из-за того, что вы используете звездочку вокруг символов круглых скобок).

Для такого общего регулярного выражения я предлагаю вам не изобретать велосипед. Вы можете сослаться на некоторые уже созданные регулярные выражения, которые легко найти в Интернете. Например, вы можете обратиться к этому сообщению, хотя в сообщении используется javascript вместо Python , регулярное выражение просто похоже.

person SeaBean    schedule 19.02.2021
comment
Думаю, теперь я понимаю. Благодарю вас! - person PineNuts0; 20.02.2021
comment
@PineNuts0 Добро пожаловать! Если вы считаете, что мой ответ дает вам подсказки о том, о чем вы спрашиваете, поставьте галочку. :-) - person SeaBean; 20.02.2021

Пытаться:

regex_parse4 = re.match(r'([(]*[0-9]{3}[)])\s*([0-9]{3}).([0-9]{4})', number)

Предполагается, что 3-значный код города в скобках начинается с XXX-XXXX.

Python возвращает NoneType, когда совпадений нет.

Если вышеуказанное не работает, вот полезный инструмент для регулярных выражений: https://regex101.com


Редактировать:

Другое предложение - очистить данные перед применением нового регулярного выражения. Это помогает в случаях ненормального интервала, избавления от круглых скобок и «-».

clean_number = re.sub("[^0-9]", "", original_number)
   
regex_parse = re.match(r'([0-9]{3})([0-9]{3})([0-9]{4})', clean_number)

print(f'groups are: {regex_parse}.groups()}')

>>> ('xxx', 'xxx', 'xxxx')
person nahar    schedule 19.02.2021
comment
спасибо за общий совет. фактический код не работает с приведенными мной примерами. - person PineNuts0; 20.02.2021