Возможно вы искали: 'BlackSpace'

May 15 2025 19:20:13
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96111483
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18357
• Обзор The Walking ... 18801
• Обзор DMC: Devil M... 19879
• Обзор на игру Valk... 15877
• Обзор на игру Stars! 17764
• Обзор на Far Cry 3 17948
• Обзор на Resident ... 16024
• Обзор на Chivalry:... 17508
• Обзор на игру Kerb... 17981
• Обзор игры 007: Fr... 16619
Превью о играх
• Превью к игре Comp... 17960
• Превью о игре Mage... 14464
• Превью Incredible ... 14721
• Превью Firefall 13479
• Превью Dead Space 3 16334
• Превью о игре SimC... 14730
• Превью к игре Fuse 15442
• Превью Red Orche... 15542
• Превью Gothic 3 16343
• Превью Black & W... 17354
Главная » Статьи » Разное » Регулярные выражения Perl: замена n-го совпадения (perl regexp)

Регулярные выражения Perl: замена n-го совпадения (perl regexp)

Ключевые слова: perl, regexp, (найти похожие документы)

From: Сергей Мельников <subm3@cronc.com.>
Newsgroups: email
Date: Mon, 20 Oct 2008 17:02:14 +0000 (UTC)
Subject: Регулярные выражения Perl: замена n-го совпадения

Это глава из моей книги "Perl для профессиональных программистов.
Регулярные выражения", которая вышла в изд-ве "Бином". У меня осталось
несколько авторских экз. этой книги, желающие могут заказать. E-mail
находится на моём сайте Ресурсы для вебмастеров.

Замена n-го совпадения

Рассмотрим замену n-го найденного фрагмента текста.

use locale;
my $s='Тел. 2-3344. Другой тел. 3-2233, а вот еще один тел. 4-1122';
my $count=0;
$s =~ s/(тел.s+)([d-]+)/ ++$count == 3 ? "${1}9-9999" : "$1$2"/egi;
print $s;


Напечатается строка "Тел. 2-3344. Другой тел. 3-2233, а вот еще один тел. 9-9999"

Оператор подстановки с модификатором g заменяет все найденные фрагменты
текста глобально, и ему для этого не нужен списочный контекст как
оператору поиска.

Мы хотели третий номер телефона заменить на 9-9999, но после каждого
найденного номера выполняется замена, поэтому то, что не нужно менять,
должно быть заменено на себя. Для этого мы взяли все перед номером
телефона в переменную $1, а все остальное - в переменную $2. Если
номер телефона не равен 3, то мы найденный фрагмент текста (который
соответствует всему регулярному выражению!) меняем на строку $1$2, а в
третьем случае в замене вместо номера телефона подставляем 9-9999. Для
разделения имени переменной от цифр используем фигурные скобки. Не
забываем также поставить модификатор e.

Как быть, если надо заменить n-й от конца найденный фрагмент текста,
если заранее неизвестно, сколько таких фрагментов будет найдено?
Рассмотрим такую идею.

Призываем в помощь конструкцию опережающей проверки и записываем
регулярное выражение так, чтобы оно совпало только на n-м от конца
искомом фрагменте текста, где n отсчитывается с нуля. Пусть это n
хранится в переменной $n. Попробуем вначале такую программу для решения
задачи:

#!/usr/bin/perl -w
use strict;
use locale;

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


Поясню, как она должна работать по первоначальному замыслу.

Т.к. литерал тел.s+[d-]+ в регулярном выражении будет встречаться
несколько раз, то оформим его в виде переменной $tel, которую будем
подставлять. Сформулируем задачу в терминах регулярных выражений: нам
надо найти фрагмент, соответствующий шаблону тел.s+[d-]+ за которым
(фрагментом) в тексте встречается ровно $n таких же фрагментов. Номер
телефона в таком фрагменте мы меняем на 9-9999.

Чтобы все остальное в этом фрагменте кроме номера телефона сохранилось,
мы берем это остальное в скобки и получаем подшаблон (тел.s+)[d-]+, с
которого начинается регулярное выражение. За фрагментом текста,
соответствующим этому шаблону, должен идти фрагмент (?:.*?$tel){$n}. .*
впереди него означает, что эти $n фрагментов не обязательно должны идти
сразу за первым фрагментом и друг за другом, между ними могут быть
посторонние включения, которые поглощаются конструкцией .*?. После того,
как эти $n фрагментов поглощены, не должно стоять такого же фрагмента
текста с любой позиции после этих $n фрагментов, это проверяет условие
(?!.*?$tel). Оба этих подшаблона (?:.*?$tel){$n} и (?!.*?$tel) включены
в позиционную проверку (?=...). Т.е. за найденным номером телефона
должен быть фрагмент текста, который стоит внутри всей этой проверки
(?=...).

Что ж, как будто бы все верно, начинаем проверять работу этой программы.
Задаем $n=0 и видим результат: "Тел. 2-3344. Другой тел. 3-2233, а вот еще один тел. 9-9999"

Верно! Заменился номер телефона, который стоит нулевым справа. Далее
даем $n значение 1 и смотрим результат. Вот неожиданность:
заменился первый телефон
"Тел. 9-9999. Другой тел. 3-2233, а вот еще один тел. 4-1122"

а должен был бы тот, что посередине! При $n=2 та же картина.
Видимо, где-то закралась ошибка. Можете вы найти (и исправить) ее
самостоятельно? Тогда читайте дальше.

Разберем работу этого регулярного выражения при $n=1. После того, как
нашелся первый номер телефона по подшаблону (тел.s+)[d-]+, началось
заглядывание вперед, и подшаблон (?:.*?$tel){$n} поглотил второй
телефонный номер. За ним началась проверка (?!.*?$tel), которая
закончилась неудачей, т.к. после второго телефонного номера есть еще
номер. "Не беда! - говорит механизм поиска соответствия.
Буду увеличивать значение минимального квантификатора .*? в подшаблоне
(?:.*?$tel){$n}, авось поможет." И начинает его увеличивать и пробовать
эти значения. Когда этот квантификатор захватит все до вертикальной
черты в следующей строке:
"Тел. 2-3344. Другой тел. 3-2233, а вот еще один т|ел. 4-1122"

весь подшаблон захватит фрагмент

", а вот еще один тел. 4-1122"


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

Когда речь шла о пропуске символов до закрывающей угловой скобки при
поиске ссылки, то все было просто: [^>]*, но здесь уже не один символ,
поэтому конструкция [^$tel]*, вообще говоря, не годится, у нас не просто
множество символов, а часть текста. Вот практический прием пропуска
символов до данного фрагмента текста:

(?:(?!$tel).)*$tel


Мы каждый раз в цикле проверяем, находится ли в текущей позиции фрагмент
текста $tel, и если нет, то берем следующий символ точкой. А после этого
цикла должен идти текст $tel. Такой цикл хотя и медлителен, но он
гарантирует, что мы не проскочим искомого фрагмента текста.

Вся программа теперь выглядит так:

#!/usr/bin/perl -w
use strict;
use locale;

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, которой можно присваивать значение.
1162 Прочтений •  [Регулярные выражения Perl: замена n-го совпадения (perl regexp)] [08.05.2012] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• Регулярные выражения Perl: замена n... Ukraine Vova 08.05.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка