Найти - Пользователи
Полная версия: Регулярные выражения: компактная запись повторяющихся фрагментов
Начало » Python для новичков » Регулярные выражения: компактная запись повторяющихся фрагментов
1
Ginibe
Исходные:
ось - Win XP SP3
питон - 2.7

Предмет анализа - одна строка с произвольным набором символов, читающихся как номер телефона с пояснениями. Номер в международном формате набора в Украине: +3, код Украины - 8, код города или мобильного опер-а - XXX, собственно семизначный номер или дополненный до семи цифр если он меньше - XXXXXXX. Кроме того порядок расположения, количество и вид разделителей цифр абсолютно не предсказуем. А еще могут присутствовать фразы пояснений как перед телефонным номером так и за ним.
Следующее регулярное выражение позволяет выделить такие телефонные номера, пользовался методом findall скомпилированного объкта регулярного выражения, тестирование было проведено на более чем 400 разновидных строках:
(?:(?:(?:\+)3)[-\(\) /]{0,3}8)[-\(\) /]{0,3}0[-\(\) /]{0,3}\d\d[-\(\) /]?[-\(\) /]{0,3}\d[-\(\) /]{0,3}\d[-\(\) /]{0,3}\d[-\(\) /]{0,3}\d[-\(\) /]{0,3}\d[-\(\) /]{0,3}\d[-\(\) /]{0,3}\d
(далее - полное выражение)
Бросается в глаза повтояющийся фрагмент в последней части выражения, вернее он повторяется 7 раз:
[-\(\) /]{0,3}\d
(далее - фрагмент1)
замена семикратного повторения фрагмента1 записью вида:
([-\(\) /]{0,3}\d){7}
(далее - фрагмент2)
желаемого результата не дает в действующем диалекте питона, хотя тестовый автомат на VB.NET из книги Бена Форта и RegExr на сайте http://gskinner.com/RegExr/ воспринимают такую запись (фрагмент2) действительно как семикратное повторение фрагмента1 в полном выражении и находят искомые подстроки.
Еще не дочитал Дж.Фридла, потому вопрос к знатокам: можна ли сократить запись полного выражения для диалекта питона? … уж очень длиннО…
… что то не так я понял в механизме рег.выражений питона… наверное
doza_and
регулярка -строка можно и форматированием получить
Ginibe
doza_and, если Вы имели в виду процесс ее формирования - 100% согласен, я же - про сам механизм регулярок в питоне. Я так понимаю, что если фрагмент в скобки обернул, то для питона это особый случай, сразу помещается в группу и обрабатывается как то по особому, а вот как я еще не понял до конца… но “не так как у других” :)
Надеюсь у Дж.Фридла найду пояснение этому, потому как из книжек по питону не вкурил…
agalen
Ginibe
желаемого результата не дает в действующем диалекте питона
В питоне все работает на ура.
>>> rr = re.compile( r"(?:(?:(?:\+)3)[-\(\) /]{0,3}8)[-\(\) /]{0,3}0[-\(\) /]{0,3}\d\d[-\(\) /]?(?:[-\(\) /]{0,3}\d){7}" )
>>> rr.match( "+380441234567" ).group(0)
'+380441234567'
Приведи пример, который не работает в питоне, но при этом работает на том сайте.
Ginibe
agalen
agalen
Приведи пример, который не работает в питоне, но при этом работает на том сайте.
>>> from re import *
>>> s0 = '+3 8(066) 3268813;'
>>> mask = compile ("(?:(?:(?:(?:\+)3)[-\(\) /]{0,3}8)[-\(\) /]{0,3}0[-\(\) /]{0,3}\d\d)([-\(\) /]{0,3}\d){7}")
>>> mask.findall (s0)
['3']
RegExr регулярку
(?:(?:(?:(?:\+)3)[-\(\) /]{0,3}8)[-\(\) /]{0,3}0[-\(\) /]{0,3}\d\d)([-\(\) /]{0,3}\d){7}
хавает и подсвечивает желаемый результат.
А вот питон - хрена, только последнюю цифру.
АшИпКу понял: повторяющийся фрагмент не содержал метасимвольного выражения ?:. Что то я не вкурил о метасимвольном выражении ?:. У Бен Форта оно описывается как аналог условного оператора, а в переводных буках про питона ничего толкового не нашел… наверно невнимательно читал…
Если есть терпение - прошу пару пояснений к метасимвольному выражению ?: в моем случае, именно для повторяющегося фрагмента, пожалста…
doza_and
В этой задаче важно правильно сформулировать что вы хотите.
Если не сложно примеры приведите какие должны быть номера
почему так нельзя?
s=re.sub(r"[^\d]","",'+3 8(066) 3268813;')
if len(s)==6:
....
Сам телефон с этим прекрасно справляется
agalen
Если в регулярном выражении есть хоть одна группа (т.е. скобки без ?: ), то findall возвращает только список этих групп. И еще - не забывай ставить r“”.
>>> from re import *
>>> s0 = '+3 8(066) 3268813;'
>>> mask = compile(r"(?:(?:(?:(?:\+)3)[-\(\) /]{0,3}8)[-\(\) /]{0,3}0[-\(\) /]{0,3}\d\d)(?:[-\(\) /]{0,3}\d){7}")
>>> mask.findall(s0)
['+3 8(066) 3268813']
Ginibe
doza_and, привожу несколько строк из которых необходимо выудить номера (владельцев телефонов, приколистов и спамеров прошу не волноваться - номера изменены до “ненабираемости” или “несоответствия”):
059-499-82-99; 090-995-54-92;
058-352-54-55; 452-98-44;
550-98-45; 030-323-83-50;
093-322-35-48; ф438-89-32;
589-49-52ф 030-225-44-98 Игорь;
0555853330 ,0952889040;
(0534) 252-253, 258-328;
095 458 08 03 раб-448 25 35;
моб.058 408 23 28 моб.о058 582 80 89;
055 489 90 82;
599-35-44 (переадресация);
055-954-05-58; 392-88-88фвит;
022-595-08-33 *222;
449-83-09; -04; -05; -02; -05ф;
058 309 20 52 / 093 549 58 85;
428 83 93 раб. 8 058 888 59 52 моб;
030-84-22-898, 42-59вн;
395-95-88 Ольга григорьевна 095-358-59-83;
058-258-29-99 (333-99-35 для Дегтяря);
0980398498 и 0558995955 и 0958353858;
+580589533888; +580304909998;
030-285-95-09 ф 554-43-89 (90шт.);
(030) 850-45-38, (05234) 3-43-83;
(058)-395-00-99; 242-04-52 приемная;
030 538 92 05 дом - 482 80 29;
Алексей 258-58-85; (058)-438-89-88;
428 83 93 раб. 8 058 888 59 52 моб;
по телефону 093 489 04 52 в понед. ответит Андрей;
099 209 49 38, оплата без нал, номер проекта KN-90-002;
0995002258 или 0955939858;;
058 455 32 23 (Сергей 095 358 23 50)
459-59-59 + 444 (офис) моб: 449-5203 055-420-50-82;
8055-889-23-88(моб) 022-242-08-95(дом);
(030)-225-23-93; 295-95-04 факс ВАТ "Универмаг Украина";
058-3844550 Игорь Витальевич;
209-43-45 (соединить с Ниной или Сергей Васильевич);
358-05-02 Пр-во IREX;
330-28-39 8-055-24-98-984;
80583585389,80358883995;
349-09-82; (030)-299-50-89;
8-055-830-85-89 (пожалуйста утром позвоните);
80559532854: 2584853;
8(028)8998885, 8(028)8445254;
3949503, 8058 9492090, 8095 0949430;
(095)-999-45-95; (055)-59-88-098;
058-398-90-80 (058-282-48-42 Иван);
(030) 555-35-04 сам (030) 955-88-55 жена;
059 -- 299-05-58 и 059 -- 299-05-04 (Андрей);
С поставленной задачей вполне справляется регулярка:
mask = re.compile(r"(?:(?:(?:\+?)3)[-\(\) /]{0,3}8)[-\(\) /]{0,3}0[-\(\) /]{0,3}\d\d[-\(\) /]?(?:[-\(\) /]{0,3}\d){7}|"+
r"(?:0)[-\(\) /]{0,3}\d\d[-\(\) /]?(?:[-\(\) /]{0,3}\d){7}|"+
r"[2-5](?:[-\(\) /]{0,3}\d){6}")
далее из каждой строки результата findall будут удалены НЕцифры и номера внесены в БД.

Предвосхищая советы о маске ввода для номера телефона, сообщаю, что источником данных строк являются уже существующие почтовые сообщения, которые предстоит обработать и внести данные в БД.


agalen, благодарен за подсказки, еще раз перечитал в буках моменты на которые ты обратил внимание, вкуриваю потихоньку… умные книги :)

P.S. Наконец то дочитал у Дж.Фридла до описания метасимвольного сочетания (?:…), цитирую:
Дж.Фридл
Вместо конструк-ции (…) производящей группировку с сохранением, используется специальная разновидность круглых скобок (?:…), которая обеспечивает группировку без сохранения. При такой записи «открывающая круглая скобка» состоит из трех символов (?:, что выглядит довольно странно. В данном случае вопросительный знак не имеет отношения к «необязательному» метасимволу ?.
Под “сохранением” Дж.Фридл имеет ввиду как раз выделение в порядковую группу, значение которой можна получить через соответствующую переменную.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB