Perl - статьи

ba2f5a3f

Определения


Регулярные выражения в perl одна из самых мощных его возможностей. Они позволяют сопоставлять текст с указанным шаблоном, разбивать текст в массив по шаблону, производить замену текста по шаблону и многое многое другое. Так-же иногда регекспами называются операторы поиска и замены.

Оператор q(text) заменяет строку text на строку, заключенную в одинарные кавычки(например если в q(text) поставить символ q(text\n), то напечатает text\n , т.е. \n это два символа, подобно print 'amam $file' напечатает amam $file). В данном случае почти все специальные символы не будут интерпретироваться внутри q(), исключая '\'

$some=q(Don't may be);

Оператор qq~text~; (вместо значка ~ можно ставить например знак |) позволяет работать со строками и многострочными текстами. пользуясь этим оператором можно выводить целые куски html-кода и писать в этом коде имена скалярных переменных.

Оператор qw("text") разбивает строку на массив слов.

@mass=qw("я вышел погулять и увидел как через реку строят новый мост"); #хотя с настроенной локалью будет работать и @mass=qw(я вышел погулять и увидел как через реку строят новый мост); for(@mass){print $_,"\n"}

Оператор qr/pattern/ ключи - imosx

работает подобно регулярному выражению s/.../.../

$rex=qr/my.STRING/is; s#$rex#foo#; #тоже самое, что и s/my.STRING/foo/is;

Результат может использоваться подобно вызову подпрограммы(см perldoc perlop Regex quote like operator)

$re=qr/$pattern/; $string=~/foo${re}bar/; $string=~$re; $string=~/$re/;

Ключи imosx стандартные(см. ниже)

Оператор qx/STRING/ работает как системная команда, подобно $output = `cmd 2>$1`;. Программа, иллюстрирующая использование данного оператора:

#!/usr/bin/perl qx[dbfdump --fs="\x18" --rs="\x19" pdffile.dbf >pdffile.txt];



файл pdffile.dbf содержит memo-поля(memo-поле содержит ссылку, подобно функции seek, на текст в файле с расширением *.fpt), которые при помощи DBI.pm мне когда-то давно выудить не удалось. Принимает разрешения FoxBASE4 и дампит файлы со встроенными memo-полями в текстовый вид. Т.е. таким образом получилось вытащить информацию из файла memo-типа *.fpt.


Допустим используя команду $perl_info = qx(ps $$); мы выводим информацию о текущем процессе запущенного скрипта(каждая запущенная программа в UNIX имеет свой собственный уникальный идентификатор, который содержится во встроенной переменной $$ - достаточно уникальное число, можно использовать почти как счетчик случайных чисел). Если сказать $shell_info = qx'ps $$'; то выведет информацию о самом ps. Т.е. скобки осуществляют своеобразное экранирование от двойной кавычки.

В перл есть три основных оператора, работающих со строками:

m/.../ - проверка совпадений (matching),

s/.../.../ - подстановка текста (substitution),

tr/.../ - замена текста (translation).

Опертаор m/.../ анализирует входной текст и ищет в нем подстроку совпадающую с указанным шаблоном (он задан регулярным выражением). Оператор s/.../.../ выполняет подстановку одних текстовых фрагментов вместо других, при помощи регулярных выражений. Оператор tr/.../.../ заменяет выходной текст, но при этом он не использует регулярные выражения, осуществляя замену посимвольно.

Оператор m/шаблон/ - поиск подстроки по определенному шаблону. Например print "$1 г.\n" while m!((\d){4})!g найдет и выведет все даты в переменной $_. В шаблоне не важно, что будет его ограничителем. Например при поиске гиперссылок, которые зачастую содержат символы /, разумнее пользоваться не /, а например # или ! как символами ограничителями. В таком случае шаблон будет более прост для понимания другим программистам, да и немного короче. В perl оператор m/.../ используется очень часто, и поэтому используется сокращение, без начальной буквы m. Если начальная буква есть, то в качетсве символов ограничителей можно исползовать любой другой символ.

Для оператора m/pattern/ есть 6 параметров: gimsxo

m/foo/g говорит компилятору найти все foo в тексте, в то время как m/foo/ найдет только первое вхождение подстроки foo в строке $_. В строке $_ содержится обычный текст, как и в переменной $text$, $_ такая-же переменная, только она существует всегда и вводится, когда не определена специально другая, по умолчанию.



Например можно сказать for (@mass){print $_,"\n"} или for $elem (@mass){print $elem,"\n"}. Эти две строчки делают одно и то-же, но в первом случае запись короче, да и зачастую бывает удобно использовать переменную $_, например, когда нужно выделить при помощи регулярного выражения определенные данные, пользуясь перебором массива(функция map):

@res=map{/(\d\d\d\d)/} split /\s/, $texts;

что эквививалентно коду

push @res, $1 while m!((\d){4})!g; #(в данном случае $_=$texts)

или что эквивалентно конструкции

foreach(split /\s/, $texts){ push @res, $1 if(/(\d\d\d\d)/g) }

Следующий параметр m/foo/i, говорит о том, что не нужно учитывать регистр при поиске по подстроке.

Параметр m/foo/s говорит от том, что строка, по которой производится поиск, состоит из одной строчки.

Например нужно выцепить все url картинок из странички www.astronomynow.com, чтобы сделать локальное зеркало этой странички и пользователи могли с интересом читать последние новости астрономии:

#!/usr/bin/perl -wT use LWP::Simple; $page=get "http://www.astronomynow.com"; &getlink($page); sub getlink{ local $_=$_[0]; push(@res, "http://$2") while m{SRC\s*=\s*(["'])http://(.*?)\1\s*(.*?)WIDTH="100" HEIGHT="100"(.*?)>}igs }

В подпрограмме заводится при помощи функции local переменная, видимая только в области действия подпрограммы. Этой переменной присваивается значение переменной $page, в которой содержится текст выкачанной Simple.pm странички.

Можно сделать немного по другому, сохранить скачанную страничку в файл на диск и затем следующее:

$/="\001"; open F, "<page.html"; $page=<F>; close F; &getlink($page); ...

Встроенная переменная $/ содержит символ разделителя входных записей. Это может быть перевод каретки или, при upload far'ом на сервер файлов в не ASCI виде, она приобретают на конце строчки хитрый символ ^M.

Если $/ переопределить, то можно свободно пользоваться дескрипторами открытия файлов для просмотра многострочного текста(m/pattern/s). Например когда открывается файл при помощи функции open F, "<file.txt"; @mass=<F>, то присваивая дескриптор F массиву в массиве появятся строчки, разделенные символом, содержащимся в $/.



Переопределив $/ можно запросто написать:

open F, "<file.txt"; $mass=<F>

и в переменной $ mass будет содержаться многострочный текст с точки зрения человека, но программа будет видеть этот текст как одну строку и по тексту можно будет запросто пройтись поиском m/pattern/igs и выделить все необходимые подстроки.

Параметр m/foo/o говорит от том, что шаблон нужно компилировать только один раз. Если оператор используется в сочетании с операциями привязки =~ и отрицание !~, то строкой, в которой ведется поиск, является переменная, стоящая слева от операции привязки. В противном случае поиск ведется в строке $_.

Оператор s!pattern!substring! - поиск в строке по шаблону pattern и замена найденного текста на substring. Как и для оператора m/.../, косую черту можно не ставить, пригоден любой символ, который не находится в противореции с заданным выражением. Не рекомендуется использовать в качестве ограничителей ? и '.

s!/usr/local/etc/!/some/where/else! - заменяет путь.

s(/usr/local/etc/)(/some/where/else)g - заменяет все встречающимеся пути до файла.

параметры: egimsxo

e - указывает, что substring нужно вычислить.

например нужно переделать все escape последовательности, для этого вызывается соответствующая подпрограмма: $text =~ s/(&.*?;)/&esc2char($1)/egs;

т.е. из регулярного выражения происходит вызов подпрограммы.

g - заменить все одинаковые компоненты, а не один, как в отсутствии ключа g.

i - не учитывать регистр.

m - строка, в которой происходит поиск, состоит из множества строк.

s - строка, в которой происходит поиск, состоит из одной строки.

x - сложный шаблон, т.е. можно писать не в строчку, а для упрощения понимания разбивать шаблон на несколько строк, примеры об этом ниже.

o - компилировать шаблон один раз.

Допустим нужно сделать поисковик, который ходит по директориям на сервере, но некоторые директории типа /cgi-bin/ и т.п. индексировать нельзя. Объявляем переменную, которая будет содержать регулярное выражение, в данном случае перечисление или img или image или temp или tmp или cgi-bin:



$no_dir = '(img|image|temp|tmp|cgi-bin)';

Ключи регулярного выражения m#$no_dir$#io говорят о том, что компилировать содержимое $no_dir нужно только один раз(ключ o) и также еще не учитывать регистр(ключ i).

Оператор tr/выражение1/выражение2/, ключи cds

Смысл: замена выражения1 на выражение2. Если указан ключ с, то это инверсия выражения1, т.е. в выражение один не входят содержащиеся в нем символы. если указа ключ d, то значит стереть замененные символы. Если указан ключ s, то значит заменить многочисленные повторяющиеся символы на одиночный символ.

Оператор y/выражение1/выражение2/(ключи cds), равносилен оператору tr.

Например в поисковой системе нужно приводить запрос в нижний регистр, дабы не зависеть от настроек локали:

$CAP_LETTERS = '\xC0-\xDF\xA8'; $LOW_LETTERS = '\xE0-\xFF\xB8';

$code = '$html_text =~ '; $code .= "tr/A-Z$CAP_LETTERS/a-z$LOW_LETTERS/"; $down_case = eval "sub{$code}";


Содержание раздела