Регулярные выражения Perl и их применение


         

Замена n-го совпадения - часть 3


my $s='Тел. 2-3344. Другой тел. 3-2233, а вот еще один тел. 4-1122'; my $tel='тел\.\s+[\d-]+'; my $n=2; $s =~ s/(тел\.\s+)[\d-]+ # ищем слово "тел." + номер (?=(?:(?:(?!$tel).)*$tel){$n} # за которым $n раз идет "тел." + номер (?!.*?$tel) # после чего не встречается "тел." +номер )/${1}9-9999/isx; print $s;

Она верно заменяет нужный телефонный номер, а если задано слишком большое значение для $n, которого нет, замена не производится. Обратите внимание, что в подшаблоне (?!.*?$tel) мы не стали заменять конструкцию .*? на новую, т.к. здесь она работает правильно: если впереди есть текст, соответствующий шаблону .*?$tel, то он будет найден и негативная опережающая проверка (?!.*?$tel) вернет ложь.

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

Атомарная группировка в этом шаблоне пришлась бы кстати. Например, подшаблон [\d-]+ можно заключить в атомарные скобки, т.к. нет смысла возвращать цифры номера телефона, это не приведет к совпадению.

Другой способ заменить n-е от конца совпадение - повторять в цикле while поиск номера телефона, взяв его в захватывающие скобки, и запоминать в массивы значения $-[1] и $+[1]. Затем отсчитать от конца массивов $n, получить смещение начала и конца нужного телефонного номера и воспользоваться функцией substr, которой можно присваивать значение.




Содержание  Назад  Вперед