Perl: регулярные выражения, ввод и вывод данных, поток управления.

Регулярные выражения в Perl используются путем "привязки" строк к операциям над регулярными выражениями, а именно с помощью оператора связывания =~. Например, при выполнении кода

if  ($text =~ m/ab+c/)   {

проверяется, совпадает ли строка, хранимая в переменной $text, с регулярным выражением ab+c. Для выполнения действий по умолчанию над строкой, в которой хранится результат предыдущей операции, т.е. $_, можно просто опустить имя переменной и оператор связывания. На самом деле можно опустить и оператор т, поскольку эта операция по умолчанию приводит к совпадению.

if  (/ab+c/)   {

Подстановки работают аналогично.

$text =~ s/etc\./and so on/g;             # Замена текста в строке $text, ИЛИ

s/etc\./and so on/g;                             # Применительно к переменной $_

Мы вставили здесь модификатор д, чтобы заменить не просто первый экземпляр подстроки "etc." вместе с подстрокой "and so on", а все найденные экземпляры. Помимо модификатора g (который применяется для поиска множественных совпадений), часто используются и другие: модификатор i, чтобы игнорировать регистр букв; модификатор s, чтобы "нацелить" точку (.) на совпадение с символами новой строки; и модификатор ш, чтобы с помощью маркеров "А" и "$" искать совпадения в начале и конце отдельных строк, а не только в начале и конце обрабатываемого текста.

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

#!/usr/bin/perl

$names = "huey dewey louie"; $regex = 1 (\w+) \s+(\w+)\s+(\w+)1;

if ($names =~ m/$regex/) {

print "l-oe имя $1.\п2-ое имя $2.\n3-e имя $3.\п";

$names =~ s/$regex/\2 \1/;

print "Новые имена \"${names}\11. \п"; } else {

print qq{"$names" не совпадает с "$regex".\n}; }

Вот как выглядит результат выполнения этого сценария.

$ peri testregex

1-ое имя huey.

2-ое имя dewey.

3-е имя louie.

Новые имена "dewey huey".

Этот пример показывает, что символы // позволяют раскрыть переменные, т.е. регулярное выражение необязательно должно быть фиксированной строкой. Обратите внимание на оператор qq — это еще одно имя для оператора заключения в двойные кавычки. •

После реализации совпадения или подстановки переменные $1, $2 и так далее соотносятся с содержимым круглых скобок в регулярном выражении. Содержимое этих переменных также доступно в самом процессе замены, в контексте которого они "именуются" как \1, \2 и т.д.

 

Ввод и вывод данных

Открывая файл для чтения или записи, вы определяете так называемый дескриптор файла, чтобы идентифицировать соответствующий канал. В приведенном ниже примере переменная INFILE служит дескриптором для файла /etc/passwd, а переменная 0UTFILE — дескриптором, связанным с файлом /tmp/passwd. Используемое в цикле while условие <infile> аналогично рассмотренному выше выражению о, но имеет свою специфику, связанную с данным конкретным дескриптором файла. Здесь считыва-ются строки из файла с дескриптором infile до тех пор, пока не обнаружится конец файла, что и остановит работу цикла while. Каждая строка размещается в переменной $_.

#!/usr/bin/perl

open(INFILE, "c/etc/passwd") or die "He удается открыть /etc/passwd"; open(OUTFILE, ">/tmp/passwd") or die "He удается открыть /tmp/passwd";

while (<INFILE>) {

($name, $pw, $uid, $gid, $96003, $path, $sh) = split /:/;

print OUTFILE "$uid\t$name\n"; }

Функция open возвратит значение "Истина", если файл успешно откроется, тем самым "замкнув" (т.е. сделав необязательным) вычисление частей die, поскольку результат вычисления всего выражения уже не изменится. Рег1-оператор or подобен оператору I | (который также есть в Perl), но с более низким приоритетом. Оператор or в общем случае предпочтительнее, если вы хотите подчеркнуть, что прежде, чем Perl переключит "свое внимание" на последствия неудачного исхода операции, должны быть выполнены все действия, указанные в левой части выражения.

Синтаксис Perl для задания способа использования каждого файла (для чтения, записи или добавления в конец) отражает возможности, заложенные в командной оболочке. Кроме того, использование таких имен файлов, как "/bin/df | ", позволит открывать входные или выходные каналы связи с командами оболочки.

 

Поток управления

В приведенном ниже примере представлена Рег1-версия уже знакомого вам bash-сценария, в котором проверялась достоверность аргументов командной строки (для сравнения можете вернуться к разделу "Функции и аргументы командной строки" этой главы). Обратите внимание на то, что Perl-конструкция if не оснащена ни ключевым словом then, ни каким-либо признаком завершения — блок операторов здесь просто заключен в фигурные скобки.

Для того чтобы обеспечить выполнение любого отдельного оператора при соблюдении некоторого условия, вы можете добавлять постфиксный вариант оператора if (или его обратную версию unless).

#!/usr/bin/perl

sub show_usage {

print shift, "\n" if scalar(@_); print "Применение: $0 source_dir dest_dir\n"; exit scalar (@_)? shift: 1; } if (0ARGV != 2) {

show_usage;

} else { # Существует два аргумента ($source_dir, $dest_dir) = 6ARGV;

show_usage "Недопустимый каталог-источник" unless -d $source_dir; -d $dest_dir or showusage "Недопустимый каталог-приемник";

Здесь две строки, которые используют унарный Рег1-оператор -d для проверки существования каталогов $source_dir и $dest_dir, эквивалентны. Вторая форма (с оператором -d в начале строки) предпочтительнее, поскольку утверждение используется в начале строки, где оно заметнее всего. Однако применение оператора or, обозначающего в противном случае", несколько сомнительно; и многих, кому приходится разбираться, в чужом коде, это сбивает с толку. Переменная массива в скалярном контексте (заданном оператором scalar в данном примере) возвращает количество элементов в массиве. Это значение на единицу превышает значение $#аггау (как всегда, в Perl предусмотрено несколько способов получения одного и того же результата).

Функции в Perl принимают аргументы в массив с именем @_. Обычной практикой считается в Perl получать доступ к ним с помощью оператора shift, который удаляет первый элемент массива аргументов и возвращает его значение.

Эта версия функции showusage принимает необязательное сообщение об ошибке для вывода на печать. Если вы предоставляете сообщение об ошибке, то можете также предоставить специфический код выхода. Тернарный оператор? г оценивает свой первый аргумент; если оценка даст значение "Истина", то результатом всего выражения станет значение второго аргумента, в противном случае — третьего.

Как и в среде bash, Perl имеет специальное условие "else if", но его ключевым словом является elsif, а не elif. (Для тех, кто использует оба языка, эти забавные пустяковые различия либо заострят их ум, либо — наоборот.)

Как показано в табл. 2.5, Рег1-операторы сравнения не совпадают с аналогичными операторами в оболочке bash: строки используют текстуальные операторы, а числа — традиционную алгебраическую запись.

В Perl у вас есть все операторы тестирования файлов, показанные в табл, за исключением операторов -nt и -ot, которые доступны только в среде bash.

Подобно оболочку bash, язык Perl предоставляет два типа цикла for. При использовании более распространенной формы цикла for обеспечивается выполнение итераций с проходом по всем элементам явно заданного списка аргументов. Например, в приведенном ниже коде перебираются по очереди элементы списка названий животных (ani mals) и выводятся по одному на строке.

@animals = qw(lions tigers bears); foreach $animal (@animals) {

print "$animal \n"; }

Также вы вправе использовать цикл for в стиле языка С.

for ($counter=l; $counter <= 10; $counter++) {

printf "$counter "; }

Хотя мы продемонстрировали применение циклов с разными ключевыми словами — for и foreach, на самом деле в обоих случаях работает одно и то же ключевое слово, т.е. в Perl вы можете использовать любую форму, которая кажется вам предпочтительнее.

В версиях языка Perl до 5.10 (2007 г.) не было явно определенных операторов case или switch, но, как уже подчеркивалось не раз, один результат можно получить несколькими путями. В дополнение к очевидному, но громоздкому варианту каскадирования операторов if, можно прибегнуть к еще одному способу использования оператора for, в котором главное — установить переменную $_, сравнить ее с нужными значениями и после выполнения соответствующих действий обеспечить выход из контекста (с помощью оператора last).

for ($ARGV[0]) {

m/Awebsphere/ && do { print "Инсталляция для websphere\n"; last; }; m/Atomcat/   && do { print "Инсталляция для tomcat\n"; last; }; m/Ageronimo/  && do { print "Инсталляция для geronimo\n"; last; };

print "Предоставлен недопустимый вариант.\n"; exit 1; }

Здесь регулярные выражения по очереди сравниваются с аргументом, сохраненным в переменной $_. При неуспешном результате сравнения в левой части операции & & правая часть уже не вычисляется и управление передается следующему оператору. Если же происходит совпадение с некоторым регулярным выражением, выполняется соответствующий ему блок do, после чего остается лишь "красиво уйти". Немедленный выход из блока for обеспечивают операторы last.

 

Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.