| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Perl: Регулярные выражения > Не учитывать совпадение при определенных условиях |
| Автор: Akella 25.5.2012, 09:15 | ||||||
Есть выражение для поиска номеров телефонов:
но в тексте часто встречается не только номер телефона, но и цена, или какой-нибудь номер, например, номер объявления
Вопрос. Как построить выражение, которое будет пропускать такие вот совпадения, если в совпавшем тексте найден нежелательный(е) символ(ы)? |
| Автор: Pfailed 25.5.2012, 13:26 |
| Например так: http://forum.vingrad.ru/index.php?showtopic=339840&view=findpost&p=2413918 |
| Автор: Akella 25.5.2012, 14:03 |
| не доходит, а можно конкретнее? |
| Автор: Pfailed 25.5.2012, 17:59 | ||
| Например здесь мы ищем цифры. Но если перед цифрами знак номера, то такие цифры нам не подходят. На выходе вторая match группа содержит 1234.
Словами это выражение: ( 1-я альтернатива - найти знак номера, затем возможно пробелы 2-я альтернатива просто разделитель отделяющий цифры ) затем цифры, которые мы ищем просим движок рег выражений не возвращаться на позицию до текущей если поиск потерпит неудачу говорим что поиск неудачен если найдена 1-я альтернатива Таким образом: движок находит "№ 4444444" - 1-я альтернатива получает указание что поиск неудачен - FAIL возвратиться за 4444444 он уже не может - SKIP ищет далее и находит уже 2-ю альтернативу "1234" (действительно тут нет знака номера) 2-я альтернатива - это не первая -> поиск успешен Используя такую технику можно создавать достаточно сложные условия для выражений, которые не должны встречаться. |
| Автор: alezzz 25.5.2012, 20:48 |
| а возле номера телефона есть за что зацепться, например "тел." или код города в скобках? не в тему, недочитал и непонял суть вопроса. |
| Автор: Akella 26.5.2012, 19:45 |
| а как насчет просмотра вперед или назад http://ru2.php.net/manual/ru/regexp.reference.assertions.php (?<=bullock|donkey) |
| Автор: Pfailed 26.5.2012, 21:17 |
| Просмотр вперед годится, но просмотр назад в Perl должен быть фиксированой длинны, т.е никаких "*" или "+". Хотя в некоторых других языках, .Net например, такого ограничения нет. |
| Автор: Akella 21.6.2012, 13:33 | ||||
| Не понял, что не так. Вот выражение
Вот текст:
Выражение находит все три группы цифр, в том числе и 68651705, хотя это нужно пропускать Что не так в этом выражении? |
| Автор: DurRandir 21.6.2012, 16:05 | ||
| Много почему)) 1. Потому что ?! - это look-ahead assertion. А look-behind - это ?<! 2. Заменили, отлично. Но теперь матчинг для выражения №1234567 будет начинаться не с позиции №-->1<--2345, а с позиции №1-->2<--345, т.е. просто пропускает 1ю цифру. Поэтому добавим ещё одно условие - ?<!\d Итого, получается что-то вроде (+я свернул общий хвост у выражений)
|
| Автор: Akella 21.6.2012, 16:14 |
всё равно находит |
| Автор: DurRandir 21.6.2012, 18:11 | ||
Я проверял на приведённой строке. Если какие-то другие данные - покажите. |
| Автор: Akella 22.6.2012, 08:49 | ||
у меня №, а не # Добавлено через 48 секунд
да, это я уже ещё вчера понял :( |
| Автор: Akella 22.6.2012, 09:08 | ||||||
Что-то у Вас тут напутано со скобками, как мне кажется Добавлено через 1 минуту и 45 секунд Вот это выражение вообще ничего ненаходит:
Добавлено через 2 минуты и 25 секунд а вот это работает:
Добавлено через 3 минуты и 35 секунд Но всё равно находит: ![]() Добавлено через 3 минуты и 47 секунд Может дело в знаке №? Добавлено через 4 минуты и 38 секунд Да, действительно, если изменить в тексте объявления № на # и в выражении, то всё ок |
| Автор: DurRandir 22.6.2012, 14:14 |
| >Вот это выражение вообще ничего ненаходит А вы не в перле смотрите, судя по скриншоту. Там концовка - /g - модификатор поиска всех совпадений, и требует стартового слеша / - они играют роль скобок-ограничителей. >всё равно находит Возможно, проблема в юникоде/кодировках? Я потому и проверял на ASCII-строке, чтобы это не влияло. |
| Автор: Akella 22.6.2012, 14:39 |
| ну да, наверное, у буржуев ведь нет знака № Добавлено через 11 секунд и программа не юникодная Добавлено через 39 секунд в общем я перешёл на #, пока что |
| Автор: Akella 12.4.2013, 14:52 |
| Хочу поднять тему, т.к. есть ещё проблема. В тексте объявлений есть телефоны. А также есть вот такой текст: решения соответствуют требованиями СНиП 31-01-2003 Здания Получается так, что выделенная группа цифр определяется, как номер телефона. Можно что-то придумать такое, что если перед номером есть слово: "СНиП ", то игнорировать найденный текст? |
| Автор: Pfailed 12.4.2013, 15:36 |
| Как была решена предыдущая проблема? |
| Автор: Akella 12.4.2013, 16:21 | ||
ну с одним символом проблемы нет, а как задать конкретное слово? Например, "СНиП " |
| Автор: Pfailed 12.4.2013, 17:18 |
| На мой взгляд некорректное выражение. Удовлетворяет строке: решения соответствуют требованиями #01-01-2003 Здания. А должно ли? |
| Автор: DurRandir 12.4.2013, 18:16 | ||||
Я бы чуть по другому сделал. Т.к. перед датой может не только "СНИП" идти (и придётся составлять список слов-исключений - регулярка расползётся быстро), я бы вырезал \d{2}-\d{2}-\d{4} как невалидный формат (никто так телефон не делит). Т.е. либо задал для хвоста [\d-() ]{6,17} более строгий формат, либо добавил соответствующий assertion: (?!\d{2,2}-\d{2,2}-\d{4,4}). Итого:
*добавление* а оно же начнёт матчиться после -01-2003 В общем, лучше уточнить валидный формат или делать доп. проверку *после* поиска и выкидывать такие совпадения. Т.к. я не уверен, что даже нечто в духе
не зацепит лишнего |
| Автор: Pfailed 12.4.2013, 18:24 |
| А в чём фишка писать \d{n,n}? Разве это не эквивалентно \d{n}? Добавлено через 6 минут и 10 секунд Но и не отработает на валидной (по условию) строке: решения соответствуют требованиями -01-01-2003 Здания |
| Автор: Pfailed 12.4.2013, 18:40 | ||
Вариация на тему моего первого поста в этой теме
Уже в коде смотрим на вторую match группу. Если она определена -- берем ее значение. Если не определена -- переходим на следующую итерацию. |
| Автор: DurRandir 12.4.2013, 18:41 | ||||
Да я не везде исправил. Эквивалентно)
"Если у вас есть проблема, и вы собираетесь решать ее с использованием регулярных выражений, то у вас есть две проблемы" в полный рост, в общем то) Можно только гадать, подойдёт или не подойдёт под реальные данные, которые есть у Akella. |
| Автор: Akella 13.4.2013, 12:36 | ||||||
Не то. ![]() а НЕ должно находить Добавлено через 9 минут и 49 секунд
а вот это уже норм Добавлено через 10 минут и 8 секунд Можно его словесно расшифровать? |
| Автор: Pfailed 13.4.2013, 15:02 |
В какой match группе нашлось? Я же написал вам, что нужно смотреть только на вторую match группу. Все исключения в первую match группу, все подходящие во вторую. |
| Автор: DurRandir 14.4.2013, 21:31 | ||
Я в том посте постарался описать, как конструировать. Оно состоит из 3х частей - двух отрицательных якорей: (?<!) - не начинать матчинг, если до позиции стоит -#\d (?!) - если строка дальше попадает под формат d{2}-\d{2}-\d{4}, то так же не начинать матчинг и потом положительная проверка под подходящий формат |
| Автор: Akella 15.4.2013, 09:01 | ||
К сожалению, "смотреть" только туда или только сюда - не подходит, потому что в одном случае будет это выражение, а в другом случае будет другое выражение, но программа одна на всех, как говорится. Можно менять только образец (выражение поиска). |
| Автор: tishaishii 14.9.2018, 20:36 |
| Создавал такое рег.выр. импирически около 3х лет. Задача была вынимать объявления из отсканированных и распознанных объявлений, преобразованных в HTML. И нужно было искать номера телефонов в БД, чтобы показывать, обработан ли податчик объявления. В общем, импирически, рег.выр. хранился в отдельном файле около 2х кб + дополнительный анализ подстрок. |