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


         

Встроенный код и интеллектуализация поиска


Рассмотрим пример, когда встроенный код помогает сделать поиск более интеллектуальным. Путь нам надо найти в тексте самое большое натуральное число. При поиске мы используем цикл while и модификатор g. Результат будем запоминать в переменной $n, которая вначале будет иметь неопределенное значение. Во встроенном коде мы проверяем, имеет ли переменная $n определенное значение или $n меньше очередного найденного числа. Если это так, то мы присваиваем $n новое значение. В результате $n должна хранить первое попавшееся максимальное число.

my $n; $_='20 0 36 35'; while (/(\d+)(?{$n=$+ if !defined $n || $n < $+})/g) {} print "Наибольшее число - это $n" if defined $n;

Напечатается

Наибольшее число - это 36

Этот пример можно упростить, исключив из него цикл while и модификатор g. Для этого в конец регулярного выражения добавим подшаблон (?!), который ни с чем не совпадает. Это будет заставлять механизм поиска соответствия делать возвраты при переборе, а когда возвраты исчерпаются, - продвигать начальную позицию поиска на один символ и повторять поиск.

my $n; $_='20 0 36 35'; /(\d+)(?{$n=$+ if !defined $n || $n < $+})(?!)/; print "Наибольшее число - это $n" if defined $n;

Опять напечатается, что

Наибольшее число - это 36

Относительно этого красивого примера хочу сделать такое замечание: если вы распечатаете начальные позиции поиска, то обнаружите, что благодаря работе условной конструкции (?!) поиск стартует, начиная с каждой цифры, т.е. проверяются также "числа" 6 и 5. И только по счастливой случайности это не привело к ошибке в результате. Вообще говоря, перед подшаблоном (\d+) надо поставить условие, что слева нет цифры, тогда поиск будет начинаться только с начала чисел:

my $n; $_='20 0 36 35'; /(?<!\d)(\d+)(?{$n=$+ if !defined($n) || $n < $+})(?!)/; print "Наибольшее число - это $n" if defined $n;

Обратите внимание, что поиск при использовании подшаблона (?!), если он не стоит в альтернативной конструкции и условном операторе, всегда заканчивается неудачей, а такой оператор поиска используется только ради побочных эффектов (установки нумерованных переменных), поэтому неправильно вставлять подобный оператор в заголовок цикла while и в условие оператора if.

А сейчас распространим этот пример на отрицательные числа. Надо учитывать знак минус перед числом. С циклом while и модификатором g все работает так же, как и раньше:

my ($n,$tmp); $_='-200 0 36 35'; while( /(-)? # берем минус в $1, если он есть (\d+) # берем число в $2 (?{ $tmp=$1 ? -$2 : $2; # в $tmp получаем число с учетом знака $n=$tmp if !defined $n || $n < $tmp; }) /gx) {}; print "Наибольшее число - это $n" if defined $n;




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