Шаблоны документов и perl


Содержание

Создание Excel документов с помощью Perl, с графиками и форматированием

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

К примеру, необходимо из БД MYSQL, в которой содержится информация об отелях и их рейтинге, вывести в документ имена этих отелей с их рейтингом и построить график , по полученным столбцам, сделать форматированную шапку для столбцов из русского текста.

Сделать это можно следующим образом:
1. Подготовить бинарный файл-подложку, для отображения графиков в Excel (если Вам интересно просто создание Excel файлов без графиков можете сразу начинать со второго пункта).
2. Вставить ссылку на этот файл непосредственно в программе скрипте, которая нам сгенерирует не просто заполненный Excel, но и график по необходимым.

1. Реализуем бинарный файл-подложку для последующего графика Excel документа.

1. Для вставки в Excel не только данных, но и графиков необходимо подготовить шаблон — бинарный файл. По-другому пока perl генерировать Excel документы с графиками не может, об этом можно прочитать здесь. Т.е. функция для вставки графика использует заранее подготовленный бинарник.
Для начала готовим Excel файл с настроенным графиком( в примере используется файл указанный здесь).
Для этого располагаем в нем два столбца (или столько сколько необходимо) в том же положении, в котором потом они будут в конечном файле и набираем их тестовыми данными , как показано ниже:

Располагаем график и ссылаемся в нем на эти столбцы. Настраиваем цвет и тип графика. При этом в самом графике, например в заголовке, могут использоваться русские названия.
График может быть таким:

2. Устанавливаем модуль для работы с Excel:

cpan[1]> make install clean Spreadsheet::WriteExcel

3. После распаковки модуля Spreadsheet-WriteExcel-2.26 в папке charts вызываем команду для полученного Excel файла:

# chartex -c mychart article.xls

Так мы получили бинарник mychart01.bin подоснову для Excel документа с графиком.

2. Теперь работаем непосредственно в скрипте для генерации конечного Excel документа.

1. Создаем Excel файл

my $workbook = Spreadsheet::WriteExcel->new(«/home/masha/ExampleExcel_with_Chart.xls»);

2. Подключаемся к файлу хранящему шаблон слов для шапки и для имен листов. Делаем шапку из русских, форматированных слов. Их надо хранить в отдельном файле в формате utf8.
Здесь располагается куча комбинаций, примеров и разных кодировок и разных языков /root/.cpan/build/Spreadsheet-WriteExcel-2.26/examples

my $file = ‘/home/masha/article_pattern.txt’;
open FH, ‘ add_worksheet(‘Hotels_Rating’);

Имя листа необходимо задавать по-английски, т.к. именно в данном примере с графиком он используется в функции store_formula() и не может быть русским. В целом можно создавать Excel файлы с листами на русском языке.

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

my $format = $workbook->add_format(valign=>’vcenter’,align=>’left’);
$format->set_bold();
$format->set_underline();
$worksheet1->write(‘B1’,$array[0],$format);
$worksheet1->write(‘C1’,$array[1],$format);
$worksheet1->write(‘B6’,$array[2],$format);

5. Делаем выборку из базы:

my $dbh=DBI->connect(‘dbi:mysql:example:localhost’, ‘root’, ») or die «Can’t connect»;
my $sth=$dbh->prepare(‘SELECT * FROM hotels;’);
$sth->execute();

6. Сохраняем полученные данные в столбцы документа и отключаемся от базы:

my $rows = $dbh->selectall_arrayref($sth);
$worksheet1->select();
$worksheet1->write_col(‘B2’,$rows);
$sth->finish();
$dbh->disconnect();

7. Добавляем график:

my $chart = $worksheet1->embed_chart(‘B9′,’/home/masha/mychart01.bin’);
$worksheet1->store_formula(«=Hotels_Rating!A1»);

Функция store_formula — позволяет пересчитать данные на графике заново в зависимости от текущих в документе Excel

Реализация в perl

Примеры

  1. Заменить множественные пробелы и нетекстовые символы на одиночные пробелы:

$text = «Here is the text.»
$text =

tr[\000-\040\177\377][\040]s;
print $text;
Here is the text.

Сократить удвоенные, утроенные и т.д. буквы:

$text = «Here is the texxxxxxt.»;
$text =

tr/a-zA-Z/s;
print $text;
Here is the text.

Пересчитать количество небуквенных символов:

Обнулить восьмой бит символов, удалить нетекстовые символы:

Заменить нетекстовые и 8-битные символы на одиночный пробел:

Поиск отдельных слов

Чтобы выделить слово, можно использовать метасимвол \S соответствующий символам, отличным от «пробельных»:

$text = «Now is the time.»;
$text =- /(\S+)/;
print ;
Now

Однако метасимвол \S соответствует также и символам, обычно не используемым для идентификаторов. Чтобы отобрать слова, составленные из латинских букв, цифр и символов подчеркивания, нужно использовать метасимвол \w :

$text = «Now is the time.»;
$text =

Если требуется включить в поиск только латинские буквы, надо использовать класс символов:

$text = «Now is the time.»;
$text =

Более безопасный метод состоит в том, чтобы включить в шаблон мнимые символы границы слова:

$text = «How is the time.»;
$text=

Привязка к началу строки

Началу строки соответствует метасимвол (мнимый символ) ^ . Чтобы шаблон к началу строки, надо задать этот символ в начале регулярного выражения. Например, вот так можно проверить, что текст не начинается с точки:

m/^\./) <
print «Shouldn’t start a sentence with a period!\n»;
>
Shouldn’t start a sentence with a period!

Чтобы точка, указанная в шаблоне, не интерпретировалась как метасимвол перед ней пришлось поставить обратную косую черту.

Привязка к концу строки

Чтобы привязать шаблон к концу строки, используется метасимвол (мнимый символ) $ . В нашем примере мы используем привязку шаблона к началу и к концу строки, чтобы убедиться, что пользователь ввел только слово «exit»:

Для проверки того, действительно ли пользователь ввел число, можно использо-вать метасимволы \d и \D . Метасимвол \D соответствует любому символу, кроме цифр. Например, следующий код проверяет, действительно ли введенный текст представляет собой целое значение без знака и паразитных пробелов:

$test = «Hello!»;
if($text =

/\D/) <
print «It is not a number.\n»;
>
It is not a number.

To же самое можно проделать, использовав метасимвол \d:

/^\d+$/) <
print «It is a number.\n»;
>
It is a number.

Вы можете потребовать, чтобы число соответствовало привычному формату. То есть число может содержать десятичную точку, перед которой стоит по краййей мере одна цифра и, возможно, какие-то цифры после нее:

$text= «3,1415926»;
if($text =

/^(\d+\.\d*|\d+)$/) <
print «It is a number.\n»;
>
It is a number.

Кроме того, при проверке можно учитывать тот факт, что перед числом может стоять как плюс, так и минус (или пустое место):

$text = «-2.7182»;
if ($text =

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

$text = «+0.142857142857142857»;
if ($text =

/^(+|-|)\d+(\.\d*\)$/) <
print «It is a number.\n»;
>
It is a number.

Альтернативные шаблоны, если они присутствуют, проверяются слева направо. Перебор вариантов обрывается, как только найдено соответствие между текстом и шаблоном. Поэтому, например, порядок альтернатив в шаблоне (\.\d*|) мог бы стать критичным, если бы не привязка к концу строки. Наконец, вот как можно произвести проверку того, что текст является шестна-дцатеричным числом без знака и остальных атрибутов:

$text = «1AO»;
unless (ftext =

m/^[a-fA-F\d]+$/) <
print «It is not a hex number, \n»;
>

Проверка идентификаторов

С помощью метасимвола \w можно проверить, состоит ли текст только из букв, цифр и символов подчеркивания (это те символы, которые perl называет словесными (word characters)):

/^\w+$/) <
print «Only word characters found. \n»;
>
Only word characters found.

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

Наконец, для проверки, что текст является идентификатором, то есть начинаетcя с буквы и содержит буквы, цифры и символы подчеркивания, можно испольpовать команду:

$text = «X125c»;
if($text=

/^[A-Za-z]\w+$/) <
print «This is identifier.\n»;
>
This is identifier.

Как найти множественные совпадения

Для поиска нескольких вхождений шаблона можно использовать модификатор g . Следующий пример, который мы уже видели ранее, использует команду m/. / с модификатором g для поиска всех входжений буквы x в тексте:

$text=»Here is texxxxxt»;
while($text=

m/x/g) <
print «Found another x.\n»;
>
Found another x.
Found another x.
Found another x.
Found another x.
Found another x.

Модификатор g делает поиск глобальным. В данном (скалярном) контексте perl помнит, где он остановился в строке при предыдущем поиске. Следующий поиск продолжается с отложенной точки. Без модификатора g команда m/. / будет упорно находить первое вхождение буквы х , и цикл будет продолжаться бесконечно.

В отличие от команды m/. / команда s/. /. / с модификатором g выполняет глобальную замену за один раз, работая так, будто внутри нее уже имеется встроенный цикл поиска, подобный приведенному выше. Следующий пример за один раз заменяет все вхождения х на z :

$text = «Here is texxxxxt.»;
$text =

s/x/z/g;
print $text;
Here is tezzzzzt.

Без модификатора g команда s/. /. / заменит только первую букву х . Команда s/. /. / возвращает в качестве значения число сделанных подстановок, что может оказаться полезным:

$text= «Here is texxxxxt.»;
print (text =

Поиск нечувствительных к регистру совпадений

Вы можете использовать модификатор i , чтобы сделать поиск нечувствительным к разнице между заглавными и строчными буквами. В следующем примере про-грамма повторяет на экране введенный пользователем текст до тех пор, пока не будет введено Q , или q (сокращение для QUIT или quit), после чего программа прекращает работу:

Выделение подстроки

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

$record = «Product number:12345
Product type: printer
Product price: 5″;
if($record=

/Product type:\s*([a-z]+)/i) <
print «The product’s type Is^.\n»;
>
product’s type is printer.

Вызов функций и вычисление выражений при подстановке текста

Используя для команды s/. /. / модификатор е , вы тем самым показываете, что правый операнд (то есть подставляемый текст) — это то выражение perl, которое надо вычислить. Например, с помощью встроенной функции perl uc (uppercase) можно заменить все строчные буквы слов строки на заглавные:

$text = «Now is the time.»;
$text=

s/(\w+)/uc()/ge;
print $text;
NOW IS THE TIME.

Вместо функции uc($l) можно поместить произвольный код, включая вызовы программ.

Поиск n-го совпадения

С помощью модификатора g перебираются все вхождения заданного шаблона. Но то делать, если нужна вполне определенная точка совпадения с шаблоном, например, вторая или третья? Оператор цикла while в сочетании с круглыми cкобками, выделяющими нужный образец, поможет вам:

$text = «Name:Anne Nanie:Burkart Name:Glaire Name: Dan»;
while ($text =

/Name: \s*(\w+)/g) <
++$match;
print «Match number $match is .\n»;
>

Match number 1 is Anne
Match number 2 is Burkart
Match number 3 is Claire
Match number 4 is Dan


Этот пример можно переписать, используя цикл for:

$text = «Name:Anne Name:Burkart Name:Ciaire Name:Dan»;
for ($match = 0;
$text =

/Name:\s*(\w+)/g;
print «Match number $ <\match>is .\n»)
<>
Match nuwber 1 Is Anne
Match number 2 is Burkart
Match number 3 is Claire
Match number 4 is Dan

Если же вам требуется определить нужное совпадение не по номеру, а по содержанию (например, по первой букве имени пользователя), то вместо счетчика $match можно анализировать содержимое переменной , обновляемой при каждом найденном совпадении. Когда требуется не найти, а заменить второе или третье вхождение текста, можно применить ту же схему, использовав в качестве тела цикла выражение perl, вызываемое для вычисления заменяющей строки:

$text = «Name:Anne Name:Burkart Name:Claire Name:Dan»;
$match =0;
$text =

s/(Name:\s*(\w+))/ # начинается код perl
if (++$match == 2) < # увеличить счетчик
«Name:John ()» # вернуть новое значение
> else < ># оставить старое значение
/gex;
print $text;
Name:Anne Name:John (Burkart) Name:ClaireName:Dan

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

Как ограничить «жадность» квантификаторов

По умолчанию квантификаторы ведут себя как «жадные» объекты. Начиная с текущей позиции поиска, они захватывают самую длинную строку, которой может соответствовать регулярное выражение, стоящее перед квантификатором. Алгоритм перебора с возвратами, используемый perl, способен ограничивать аппетит квантификаторов, возвращаясь назад и уменьшая длину захваченной строки, если не удалось найти соответствия между текстом и шаблоном. Однако этот механизм не всегда работает так, как хотелось бы. Рассмотрим следующий пример. Мы хотим заменить текст «That is» текстом «That’s». Однако в силу «жадности» квантификатора регулярное выражение » .*is » сопоставляется фрагменту текста от начала строки и до последнего найденного «is»:

$text = «That is some text, isn’t it?»;
$text =

s/.*is/That’s/;
print $texts;
That’sn’t it?

Чтобы сделать квантификаторы не столь жадными, а именно заставить их захватывать минимальную строку, с которой сопоставимо регулярное выражение, после квантификатора нужно поставить вопросительный знак. Тем самым квантификаторы принимают следующий вид:

  • *? — ноль или несколько совпадений,
  • +? — одно или несколько совпадений,
  • ?? — ноль совпадений или одно совпадение,
  • ? — ровно n совпадений,
  • ? — по крайней мере n совпадений,
  • ? — совпадений по крайней мере n , но не более, чем m.

Оратите внимание, что смыслквантификатора от этого не меняется; меняется только поведение алгоритма поиска. Если в процессе сопоставления шаблона и текста прототип определяется однозначно, то алгоритм поиска с возвратами увеличит «жадность» такого квантификатора точно так же, как он ограничивает аппетит собрата. Однако если выбор неоднозначен, то результат поиска будет другим:

$text = «That is some text, isn’t it?»;
$text =

s/.*?is/That’s/;
print $texts;
That’s some text, isn’t it?

Как удалить ведущие и завершающие пробелы

Чтобы отсечь от строки начальные «пробельные символы», можно использовать, следующую команду:

$text = » Now is the time.»;
$text =

s/^\s+//;
print $texts;
Now is the time.

Чтобы отсечь «хвостовые» пробелы, годится команда:

$text = «Now is the time. «;
$text =

s/\s+$//;
print $texts;
Now is the time.

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

Например в тексте нужно найти текст, находящийся между открывающим и закрывающим тегом:

найдет все слова, стоящие между тегами и .

В регулярных выражениях пристутствует своя семантика: быстрота, торопливость и возврат. Если квантификатор * совпадает во многих случаях, то в результате быдет выведен наибольший по длинне результат. Это жадность. Быстрота: поиск старается найти как можно быстрее. «Text»=

/m*/ , по смыслу символов m нет, но в результате будет возвращено значение 0 . Т.е. формально 0 и более символов.

$test=»aaooee ooaao»;
$test=

s/o*/e/;
print $test;
eaaooee ooaao

потому что 1 элемент сторки — 0 и более символов.

Если добавить квантификатор g , то результат будет таким:

т.к строка содержит 13 мест, где может встречатся o , в том числе и пустых.

Модификаторы:

  • /i игнорировать регистр
  • /x игнорировать пропуски в шаблоне и разрешить комментарии.
  • /g модификатор разрешающий выполнение поиска/замены везде, где это возможно
  • /gc не сбрасывается позиция при неудачном поиске.
  • /s разрешается совпрадение . с \n , игнорируется $* .
  • /m разрешить совпадение ^ и $ для начала и конца строки во внутренних переводах строк
  • /o однократная компиляция
  • /e правая часть s/// представляет собой выполняемый код
  • /ee правая часть s/// выполняется, после чего возвращаемое значение интерпретируется снова.

при вызове use locаle учитываются локальные настройки. Модификатор /g может заполнить массив значений @nums = m/(\d+)/g; но это сработает для ненакладывающихся совпадений. Чтобы поймать совпадения нужно воспользоваться оператором ?=. Если ширина = 0 , то механизм поиска остался на прежнем месте. Найденые данные остаются внутри скобок. Если есть модификатор /g , то текущая позиция остается прежней, но происходит перемещение на один символ вперед.

Модификаторы m и s нужны для поиска последовательностей символов, содержащих перевод строки. При s точка совпадает с \n и игнорируется $* . m делает совпадающими ^ и $ до и после \n . e правая часть выполняется как программный код: perl -i -n -p -e ‘s/(.)/lc()/g’ *.html приводит все литеры во всех файлах *.html текущей директории к нижнему регистру.

Что такое регулярные выражения?

Регулярные выражения (англ. «regular expressions», жарг. «регэкспы» или «регексы») —- современная система поиска текстовых фрагментов в электронных документах, основанная на специальной системе записи образцов для поиска. Образец (англ. «pattern»), задающий правило поиска, по-русски также иногда называют «шаблоном», «маской», или на английский манер «паттерном». Регулярные выражения произвели прорыв в электронной обработке текста в конце XX века.

Регулярные выражения (regex) являются важной составной частью текстовых редакторов, инструментов поиска и большинства основных языков программирования, которые поддерживают регулярные выражения для работы со строками. Например, Perl и Tcl имеют встроенный в их синтаксис механизм обработки регулярных выражений. Набор утилит (включая редактор sed и фильтр grep), поставляемых в дистрибутивах Unix, одним из первых способствовал популяризации понятия регулярных выражений.

Возможности

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

  • Проверять, соответствует ли вся строка целиком заданному шаблону.
  • Находить в строке подстроки, удовлетворяющие заданному шаблону.
  • Извлекать из строки подстроки, соответствующие заданному шаблону.
  • Изменять в строке подстроки, соответствующие шаблону.

Для кого этот проект?

Синтаксис языка описаний шаблонов приводится практически в любом руководстве к языку программирования, поддерживающему регулярные выражения. Но, как правило, начинающему программисту трудно сразу разобраться в обилии операторов, условных обозначений, модификаторов и метасимволов языка описаний шаблонов. Именно для начинающих программистов и предназначен проект PCRE.RU. Хотя вполне может оказаться полезным и для профессиональных программистов.

С чего начать изучение?

Начните изучение с конструктора выражений и примеров, одновременно сопоставляя полученные знания с документацией и статьями по регулярным выражениям.

Для работы конструктора регулярных выражений требуется поддержка интернет-обозревателем языка Javascript. Кроме того, конструктор имеет ряд ограничений, связанных с различной поддержкой регулярных выражений в каждом отдельно взятом интернет-обозревателе.

Обратная связь

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

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

Благодарим агентство переводов Bues.ru за локализацию англоязычных материалов и неоценимый вклад в развитие проекта.

Добавить пример

Примеры

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

Использование языка Perl и регулярных выражений / 2 марта 2007 г.

Итак, мы с вами уже кое-что умеем.

MS Word , конечно, хорош — может быть, в чём-то и хуже OpenOffice , но зато и бегает побыстрее, и стоит повсюду. Одна беда: реализация регулярных выражений в VBA доброго слова, конечно же, не заслуживает. С другой стороны — сред разработки, поддерживающих RegExp ы в полной мере, хватает, но они, как правило, не в состоянии работать со сложным форматированием документа. Как бы нам все эти вкусности объединить в одном решении.

Perl for Win32

В 1986-м году Larry Wall разработал специальный язык для создания отчётов в среде Unix . Название языку было дано в соответствии с назначением: Perl (Practical Extraction аnd Report Language). Получилось даже благозвучно. По утверждению автора, при создании языка им в первую очередь двигала лень, а значит, инструмент должен был выйти неплохой.

Упомянутые «отчёты» представляли (и до сих пор представляют) собой текстовые файлы, иногда — очень большого объёма. Таким образом, Perl с самого начала позиционировался как язык для обработки текстов. Понятно, что под Unix ом такой замечательный инструмент не засиделся: через несколько лет после появления Perl был портирован на платформу Windows , благодаря чему мы с вами, мышевозы и виндузятники, можем насладиться всеми предоставляемыми им возможностями, а в первую очередь — полноценным синтаксисом регулярных выражений, лучше которых для текста пока ещё ничего не придумано.

Диалект Perl , о котором я поведу речь, называется ActivePerl , и его совершенно бесплатно можно скачать с сайта ванкуверской компании ActiveState.

Не думайте, что я собираюсь всерьёз учить вас программировать. Всё, что мне известно о Perl , не покрывает и десятой доли его возможностей. Я просто предлагаю к рассмотрению парочку скриптов, которые мне как текстовому процессору показались очень удобными и полезными. Если же кто-то захочет узнать немного больше — добро пожаловать в «Уроки веб-дизайна», один из которых как раз и посвящён азам упомянутого языка.

Установка и настройка

Тут особенно мудрить нечего. Качаем инсталлятор Perl и запускаем его, указав C:\Perl в качестве директории для установки. Если вам по какой-то причине приспичило инсталлировать ActivePerl в другое место, в скриптах, о которых пойдёт речь дальше, придётся поменять первую строчку

на соответствующую выбранному вами пути. Заметьте, что слеши ( / ) должны быть прямыми, а не обратными ( \ ), к которым вы привыкли под Windows .

Что же до настройки, то тут всё тоже не очень сложно. Если вдруг скрипты не заработают, запустите из командной строки ppm ( Perl Package Manager ) и добавьте отсутствующий в системе модуль Win32::OLE с помощью команды install . В общем, даже и останавливаться на этом не буду, настолько всё элементарно. Если вдруг возникнут проблемы, почитайте вот это.

Кроме того, нам с вами понадобится некий файл с шаблоном документа, который я выложу в конце статьи. Зачем — объясню чуть позже.

Скрипты Perl представляют собой простые текстовые файлы с расширением .pl , первой строкой (!) которых обязательно является shebang , говоря иначе — та самая строчка, о которой шла речь двумя абзацами выше.

Между прочим, ставить Perl , конечно, вы вовсе не обязаны: в конце статьи я собираюсь выложить и бинарные версии скриптов, не требующие никаких инсталляций. Но. как всегда, есть как минимум одно «но». Такие скрипты вы не сможете редактировать. То есть, конечно, можно будет запускать их во славу Аллаха, если мои задачи, для которых они писались, вас полностью устраивают. А если нет? Решайте сами.

Запуск макросов Word из скриптов Perl

Делается это так:

Не пугайтесь, ничего страшного тут нет. Обратите внимание на седьмую строчку. Именно в ней интерпретатор Perl , к этому моменту уже запустивший Word и открывший документ template.doc , запускает макрос Paragraph , записанный вами ранее. В общем, уже почти бинго.

Переходим к практике

Давайте наконец выясним, чего нам удалось добиться.

Perl запускает Word и прогоняет некий макрос. Отлично! Но, собственно, зачем? Мы прекрасно могли бы открыть Word , войти в меню Tools | Macros и обойтись без разных подозрительных языков. Более того, на VBA вполне можно запрограммировать пакетную обработку, при которой последовательно будут открываться и изменяться, скажем, все файлы из определённой директории. Так зачем городить огород?

Наверное, пора рассказать, откуда растут ноги у всей этой истории.

Как я уже писал, многие книжки для своей библиотеки я брал у Максима Мошкова: не ради дурацкого дублирования, а потому, что меня не устраивал вид, в котором они хранились на Lib.ru.

Книжек было много, соответственно — требовалось обрабатывать их пакетно, что VBA мог. Задачки по приведению текстов к нормальному виду иногда стояли очень интересные, и требовался синтаксис регулярных выражений, VBA недоступный. Плюс кое-какие баги, в основном с ^13 , частично описанные в предыдущей статье. Тогда и появилась идея разделения обязанностей: я хотел заставить VBA и Perl работать вместе так, чтобы каждый из них делал то, на что он лучше всего способен.

Задачу я поставил следующим образом: поскольку исходным материалом чаще всего являются текстовые файлы, пусть их открывает написанный на Perl е скрипт, он же производит основную правку, а потом уже отдаёт файлы Word у, который форматирует каждый текст уже по возможности ближе к конечному виду.

Как ни странно, получилось неплохо. Настолько неплохо, что иногда я даже низвожу до текстового формата некоторые найденные в Сети .doc или .rtf -файлы (конечно, пометив предварительно болды-италики, чтоб не потерять их) и прогоняю их через получившуюся систему обработки с целью устранения всяких глюков и вывертов, на которые оба формата способны.

Расскажу по порядку, что делает один из скриптов.

1. Читает все текстовые ( .txt ) файлы из каталога. Я обычно сваливаю поименованные файлы в ту папку, в которой лежит скрипт, запускаю последний и жду, пока он отжурчит (иногда это занимает несколько минут, всё зависит от количества и размера файлов).

2. Открывает каждый файл, читает его содержимое, обрабатывает его с помощью регулярных выражений, проделывая всё, что может Perl и чего не может VBA , в основном это всякие процедуры на границе абзацев. После этого файл отдаётся Word у. Тот открывает шаблон template.doc , вставляет в него частично обработанный текст, а затем честно прогоняет макросы Paragraph и Dashes , которые обязательно должны присутствовать в общем списке макросов Word а (можно использовать любые макросы, но их должно быть два, и именно с такими названиями; если какой-то из них вам не нужен, создайте пустой макрос, чтобы избежать прекращения работы скрипта из-за ошибки времени выполнения ( runtime error )).

3. Сохраняет документ с расширением .doc и тем же именем, что было у исходного текстового файла, и берётся за следующий. И так до конца списка.

Инструкция по эксплуатации

Для того, чтобы привести систему в работоспособное состояние, нужно очень немногое.

1. Установленный Perl со всеми необходимыми модулями (повторяю, можно обойтись бинарными скриптами, но в этом случае вы не сможете ничего менять).

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

3. Подкаталог tools , в котором должен находиться файл template.doc

Для тестирования всего вышеперечисленного достаточно положить в каталог со скриптами хотя бы 1 (один) текстовый файл и запустить один из двух скриптов. Первый предназначен для обработки текстов с условным разбиением на абзацы, второй — для безусловного разбиения. Всё. Будут ошибки или проблемы — пишите. Как работают сами скрипты — очень подробно написано в комментариях. Текстовый файл для тестирования лучше взять у Максима Мошкова.

ForCoder

Книги по Perl, скачать бесплатные книги, самоучители и учебники по Perl в хорошем качестве

Вскоре после выхода первого издания в 1991 году книга «Программирование на Perl» стала считаться неоспоримой библией по языку Perl и продолжает оставаться основным руководством по этому весьма практичному языку.

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

В этом долгожданном обновлении «Верблюда» три известных автора дополнили описание языка до его текущей версии 5.14 и добавили обзор некоторых особенностей готовящейся к выходу версии 5.16. Все большую значимость в обработке текстов приобретает Юникод, а Perl предлагает лучшую и самую безболезненную поддержку этого стандарта, тесно интегрируя Юникод во все сферы, в том числе в такой популярный механизм языка Perl, как регулярные выражения.

Данное издание охватывает следующие важные особенности языка Perl: новые ключевые слова и синтаксические конструкции, уровни ввода/вывода и кодировки, новые escape-последовательности, поддержка стандарта Unicode 6.0, групповые графемы и свойства символов Юникода, именованные сохраняющие группы в регулярных выражениях, рекурсивные и грамматические шаблоны, расширенный обзор архива CPAN и современные передовые приемы программирования.

3,284 просмотров всего, сегодня нет просмотров

Программирование на Perl

Вскоре после выхода первого издания в 1991 году книга «Программирование на Perl» стала считаться неоспоримой библией по языку Perl и продолжает оставаться основным руководством по этому весьма практичному языку.

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

В этом долгожданном обновлении «Верблюда» три известных автора дополнили описание языка до его текущей версии 5.14 и добавили обзор некоторых особенностей готовящейся к выходу версии 5.16. Все большую значимость в обработке текстов приобретает Юникод, а Perl предлагает лучшую и самую безболезненную поддержку этого стандарта, тесно интегрируя Юникод во все сферы, в том числе в такой популярный механизм языка Perl, как регулярные выражения.

Данное издание охватывает следующие важные особенности языка Perl: новые ключевые слова и синтаксические конструкции, уровни ввода/вывода и кодировки, новые escape-последовательности, поддержка стандарта Unicode 6.0, групповые графемы и свойства символов Юникода, именованные сохраняющие группы в регулярных выражениях, рекурсивные и грамматические шаблоны, расширенный обзор архива CPAN и современные передовые приемы программирования.

5,603 просмотров всего, сегодня нет просмотров

Perl-отладчик. Карманный справочник


Описание книги Perl-отладчик. Карманный справочник:
Язык Perl достаточно популярен в России. Его часто упрекают в больших неудобствах отладки приложений. Данное издание призвано исправить эгот не самый существенный недостаток языка и привлечь в ряды сторонников Ларри Уолла новых программистов. Подробно рассматривается отладчик языка Perl, использование команд, опций и переменных.

Приводятся примеры, облегчающие процесс отладки приложений. Книга будет полезна разработчикам и ИТ-специалистам, использующим язык Perl.

Содержание книги «Perl-отладчик. Карманный справочник»:

  • Что такое отладчик для Perl?
  • Зачем использовать отладчик?
  • Незнакомая территория
  • Об этой книге
  • Сценарий linecounter.pl
  • Оболочка
  • Усеченный вывод
  • Версии Perl
  • Более глубокое погружение
  • Условные обозначения
  • Благодарности и ответственность
  • Перед тем как вы приступите к отладке
  • Проверьте ваш синтаксис
  • Используйте strict
  • Предупреждения
  • Диагностика
  • Режим taint
  • Использование отладчика
  • Начало сеанса
  • Простой CGI-сеанс отладчика
  • Команды отладчика
  • Справка и выход
  • Изучение данных
  • Листинг кода и поиск
  • Продвижение
  • Действия, контрольные точки и точки наблюдения
  • Команды Perl и команды, исполняемые до и после приглашения
  • Команды оболочки и отладчика
  • Установка опций
  • Переменные отладчика
  • Переменные $DB::*
  • Переменные среды
  • Опции отладки
  • Пространства имен DB и Devel
  • Последовательность этапа выполнения
  • DB::DB()
  • DB::sub ()
  • Пространство имен Devel(-d)
  • Полезные модули
  • -DDEBUGGING
  • Справочные источники
  • Книги
  • URL
  • Онлайновые статьи
  • История
  • Графические пользовательские интерфейсы – GUI
  • Отладчики
  • Текстовые редакторы

6,773 просмотров всего, сегодня нет просмотров

Разработка Web-сайтов с помощью Perl и MySQL

Описание книги Разработка Web-сайтов с помощью Perl и MySQL:
На практических примерах описана разработка динамических Web-сайтов с помощью Perl и MySQL. Рассмотрены основные конструкции языка Perl, даны приемы написания сценариев, наиболее часто используемых в разработке Web-сайтов. Уделено внимание способам работы с базами данных посредством Perl, а также вопросам администрирования баз с помощью программы phpMyAdmin.

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

Содержание книги «Разработка Web-сайтов с помощью Perl и MySQL»:

  1. Установка программного обеспечения под Windows
  2. Основы Perl
  3. Web-программирование на Perl
  4. Основы MySQL
  5. Сплошная практика
  6. Публикация сайта

9,205 просмотров всего, сегодня нет просмотров

Automating System Administration with Perl

Описание книги Automating System Administration with Perl:
If you do systems administration work of any kind, you have to deal with the growing complexity of your environment and increasing demands on your time. Automating System Administration with Perl, Second Edition, not only offers you the right tools for your job, but also suggests the best way to approach specific problems and to securely automate recurring tasks.

Updated and expanded to cover the latest operating systems, technologies, and Perl modules, this edition of the «Otter Book» will help you:

  • Manage user accountsMonitor filesystems and processesWork with configuration files in important formats such as XML and YAML
  • Administer databases, including MySQL, MS-SQL, and Oracle with DBI
  • Work with directory services like LDAP and Active Directory
  • Script email protocols and spam controlEffectively create, handle, and analyze log files
  • Administer network name and configuration services, including NIS, DNS and DHCP
  • Maintain, monitor, and map network services, using technologies and tools such as SNMP, nmap, libpcap, GraphViz and RRDtool
  • Improve filesystem, process, and network security
  • This edition includes additional appendixes to get you up to speed on technologies such as XML/XPath, LDAP, SNMP, and SQL.

With this book in hand and Perl in your toolbox, you can do more with less — fewer resources, less effort, and far less hassle.

5,854 просмотров всего, сегодня нет просмотров

Самоучитель Perl

Описание книги Самоучитель Perl:
В книге изложены основы современного языка Perl, популярность которого постоянно возрастает, особенно в таких областях, как обработка текста, CGI — программирование, системное администрирование. Язык описан по схеме от простого к сложному: типы данных, переменные, операции, операторы и т.д. Рассматривается объектно — ориентированная технология программирования.

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

Содержание книги «Самоучитель Perl»:

  1. Введение в мир Perl
  2. Структура программы
  3. Типы данных
  4. Операции и выражения
  5. Операторы
  6. Операции ввода/вывода
  7. Работа с файлами
  8. Форматы
  9. Ссылки

9,512 просмотров всего, сегодня нет просмотров

Perl 6 и Parrot. Справочник

Описание книги Perl 6 и Parrot. Справочник:
Когда филолог Ларри Уолл создавал первую версию компьютерного языка Perl, он, наверное, не подозревал, что его детищу будет суждена долгая и увлекательная жизнь. Perl понравился администраторам и web-программистам и прочно занял свою нишу в арсенале разработчиков. У каждого языка есть свои плюсы и минусы — спорить по поводу того, какой язык лучше, можно до бесконечности.

Эта книга посвящена самой последней версии языка, который продолжает развиваться. Описываются синтаксис языка, новые возможности и идеи, рассказывается в какую сторону пойдет развитие. Книга будет полезна широкому кругу IТ-специалистов: программистам, администраторам, менеджерам.

Содержание книги «Perl 6 и Parrot. Справочник»:

  • Обзор проекта
  • Работа над проектом
  • Философия разработки
  • Базовый синтаксис
  • Подпрограммы
  • Объекты
  • Грамматики и правила
  • Внутренняя структура Parrot
  • Язык ассемблера Parrot
  • Промежуточное представление Parrot (PIR)
  • Справочник по Parrot

5,251 просмотров всего, 1 просмотров сегодня

Perl. Наглядный курс программирования

Описание книги Perl. Наглядный курс программирования:
Изложение материала в этой книге построено на рассмотрении достаточно простых примеров, с помощью которых можно быстро научиться создавать мощные сценарии и программы. Для того чтобы извлечь максимальную пользу из книги, ее необходимо читать последовательно, начиная с первой главы и заканчивая последней. В каждой из следующих глав рассматривается новый материал и способы решения определенных задач, которые во многом базируются на понимании того, что было пройдено в предыдущих главах. Ну, а после того, как вы почувствуете себя знатоком Perl и завершите чтение данной книги, она может служить в качестве информативного наглядного пособия, всегда занимающего почетное место на вашем рабочем столе.

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

5,556 просмотров всего, сегодня нет просмотров

Perl. Сборник рецептов. Для профессионалов

Описание книги Perl. Сборник рецептов. Для профессионалов:
Обширный сборник задач, решений и практических примеров для всех программистов Perl. Книга содержит сотни тщательно проанализированных «рецептов» по всем основным областям программирования: обработка данных (строки, числа, даты, массивы и хэши), поиск по образцу и замена текста; ссылки, структуры данных, объекты и классы; сигналы и исключения и т.д.

Второе издание книги было дополнено двумя новыми главами. Одна глава посвящена mod_perl, интегрированному интерпретатору Perl веб-сервера Apache, а другая — обработке данных в формате XML. Многие старые рецепты в других главах были изменены или дополнены.

Книга рассчитана на программистов, обладающих опытом работы на Perl.

7,059 просмотров всего, сегодня нет просмотров

Разработка CGI-приложений на Perl

Описание книги Разработка CGI-приложений на Perl:
Эта книга научит вас применять Perl для решения задач, необходимых в современных сетевых приложениях. Множество примеров и еще более многочисленные упражнения дают не просто полезную информацию, но и готовые программы, которые вы можете сразу поместить в свои приложения.

Книга поможет вам овладеть практическими приемами и методами, с которыми вы сможете разрабатывать на Perl любые Web-приложения на основе протокола CGI.

Основное внимание в книге уделяется важным вопросам разработки Web-приложений, таким как работа с базами данных, обработка форм и файлов, безопасность, электронная почта и работа с графикой.
Кроме того, в этой книге подробно рассматриваются некоторые более специальные темы: обработка Web-форм и получение через них данных пользователя, файлы cookie, отслеживание щелчков и счетчики доступа, применение модуля Apache mod_perl, связывание переменных с базами данных, встраивание кода Perl в HTML при помощи модуля HTML::Mason, управление документами через Web, создание динамических изображений, применение XML и его производных — RSS и RDF.

Книга рассчитана на программистов средней и высокой квалификации.

6,118 просмотров всего, 1 просмотров сегодня

Часть 1: Oсновы Perl/Tk

Серия контента:

Этот контент является частью # из серии # статей: Изучаем модуль Perl/Tk

Этот контент является частью серии: Изучаем модуль Perl/Tk

Следите за выходом новых статей этой серии.

Язык Perl обычно используется системными администраторами и разработчиками IBM® AIX®, он применяется почти на всех популярных Web-сайтах и в большинстве систем AIX. Хотя скрипты на Perl являются мощным средством, Web-интерфейс, созданный на их основе, не содержит графического оформления, и пользователю приходится набирать информацию с клавиатуры вместо того, чтобы пользоваться мышью, что может оказаться неприемлемым для заказчика. Эта проблема была решена с появлением в Perl модуля Tk. Модуль Tk позволяет администраторам и разработчикам быстро преобразовать скрипты в более удобный для пользователей вид, оснастив их графической оболочкой X11.

Что такое Perl?

Perl (Practical Extraction and Reporting Language — практический язык для извлечения данных и составления отчётов) был создан Ларри Уоллом в 1987 году для облегчения собственной работы по программированию. С тех пор Perl приобрел популярность во всем мире и стал важным инструментом для большинства администраторов и разработчиков.

Что такое модуль Perl/Tk?

Модуль Perl/Tk, также известный как pTk или ptk, — это модуль, разработанный для создания виджетов и других распространенных графических объектов, образующих графический интерфейс пользователя (GUI). Использование Perl/Tk для создания GUI делает работу с программой более удобной и помогает конечному пользователю сориентироваться в программе и ее функциях. Одним из важнейших преимуществ использования модуля Perl/Tk является кросс-платформенность — одно и то же GUI-приложение может использоваться в UNIX®, Linux®, Macintosh, Microsoft® Windows® или любой другой операционной системе, в которой установлен Perl с модулем Tk.

Где взять модуль Perl/Tk

Перед тем как написать приложение с использованием модуля Perl/Tk, необходимо иметь сам Perl и модуль Perl/Tk. Хотя Perl на большинстве компьютеров уже установлен, модуль Perl/Tk скорее всего отсутствует. Чтобы убедиться в том, что Perl установлен, введите команду perl —version . Если Perl не установлен, обратитесь к руководству по установке с сайта Perl (см. раздел Ресурсы).

После того как вы найдете Perl на своем компьютере или установите его, нужно определить, необходимо ли установить модуль Perl/Tk. Самый простой способ проверить, установлен ли какой-либо модуль Perl на компьютере – ввести команду perl -e «use module» . Чтобы убедиться в том, что на компьютере установлен модуль Perl/Tk, введите следующую команду:

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

Запомните, что синтаксис Perl чувствителен к регистру: perl -e «use Tk» и perl -e «use tk» — это две разные команды, обращающиеся к двум различным модулям (Tk и tk).

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

Если вы используете ОС UNIX или Linux, один из способов загрузить и установить модули Perl – это использовать сеть архивов CPAN (Comprehensive Perl Archive Network). Введите следующую команду:

В ОС Windows для тех же целей используется менеджер пакетов Perl (Perl Package Manager, PPM). В командной строке введите ppm для запуска графического интерфейса и загрузки модуля Tk.

После завершения установки еще раз убедитесь том, что Perl обнаружил данный модуль, введя команду perl –e «use Tk» .

Создание окна

Теперь, когда на вашем компьютере установлены Perl и модуль Tk, самое время написать первую программу с графическим интерфейсом при помощи этого модуля. Мы начнем с простой программы Hello World. При помощи вашего любимого текстового редактора создайте файл helloworld.pl и введите в него следующий текст:

Выполнение скрипта генерирует GUI-приложение, показанное на рисунке 1.

Рисунок 1. Пример скрипта Hello World

Давайте разберем данный скрипт построчно:

Первая часть ( /usr/bin/perl ) определяет расположение исполняемых файлов Perl и указывает компьютеру использовать данную копию Perl для выполнения скрипта helloworld.pl file. Вторая часть этой строки ( -w ) — это полезное средство Perl: этот параметр активирует вывод предупреждений для конечного пользователя при возникновении любых ошибок.

Комментарии и текст, который не должен обрабатываться при выполнении программы, начинаются с символа решетки # symbol:

Чтобы скрипт Perl использовал модуль Tk, модуль необходимо включить – при помощи оператора use Tk . Оператор use strict также помогает выявлению различных опечаток или логических ошибок.

Чтобы создать первичное окно приложения, используйте MainWindow и назначьте его $mw . $mw выступает в роли родителя для всех остальных виджетов.

Укажите размер окна 200 x 100 и заголовок окна «Hello World. «.

Создайте надпись в главном окне с заголовком Hello World. Оператор создания надписи завершается дополнительным методом pack , который обрабатывает геометрию объектов. Этот метод используется в виджетах для вычисления пространства, выделенного из родительского виджета; он также отображает сам виджет.

Следующая строка создает кнопку Close (Закрыть) в главном окне. При активации с помощью мыши клавиатуры эта кнопка закрывает скрипт Perl.

Так как кнопка занимает место в главном окне, вам снова необходимо использовать метод pack для расчета занимаемого пространства.

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

Виджеты

Этот раздел содержит введение в виджеты. В нем рассматривается несколько основных виджетов с примерами: фреймы, текстовое поле, поле ввода, кнопки и надписи.

Что такое виджет?

Виджет – это графический объект, выполняющий определенную функцию. Любой графический объект в модуле Perl/Tk может рассматриваться как виджет. Если вы представляете себе приложение с графическим интерфейсом, кнопки, текст, фреймы и полосы прокрутки – все это виджеты.

Следующие примеры составляют основу виджетов, обсуждаемых далее в этой статье.

Фрейм

Фрейм, в точном соответствии со своим названием (frame – рамка), представляет собой рамку или блок. Фрейм используется для группировки других виджетов.

Создайте скрипт следующего содержания:

Запуск этого скрипта генерирует GUI-приложение, показанное на рисунке 2.

Рисунок 2. Пример использования фреймов

Давайте разберем этот скрипт:

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

Создаем фрейм с главным окном в качестве родителя и указываем цвет фона – красный. В отличие от предыдущего примера, метод pack имеет несколько параметров.

Первый аргумент ipadx увеличивает ширину фрейма до 100 (50 x 2). Второй аргумент side выравнивает фрейм по левой стороне родительского объекта ( $mw ). Третий аргумент выделяет место во фрейме по оси y (по вертикали).

Следующий фрейм похож на предыдущий, но цвет его фона – синий, и он выровнен по правой стороне главного окна.

Текстовое поле

Текстовое поле создает рабочую область для редактирования текста. Создайте скрипт следующего содержания:

Запуск этого скрипта и ввод текста генерирует GUI-приложение, показанное на рисунке 3.

Рисунок 3. Пример текстового поля

В этом примере текстовый виджет создается с главным окном в качестве родителя:

Кроме изменения цвета фона, можно менять только цвет шрифта. Как всегда, для выделения места и отображения виджета используется метод pack .

Поле ввода

Поле ввода похоже на текстовое поле тем, что позволяет вводить или редактировать текст. Текстовое поле позволяет вводить многострочный текст, а поле ввода — только одну строку текста.

Создайте скрипт следующего содержания:

Запуск этого скрипта и ввод текста генерирует GUI-приложение, показанное на рисунке 4.


Рисунок 3. Пример поля ввода

Единственное отличие от текстового поля – это наименование виджета:

Однако, как показано в примере, вы можете ввести только одну строку текста.

Кнопка

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

В следующем примере используется три кнопки. Первая, с надписью Button 1 (Кнопка 1), выводит сообщение Button 1 pushed (Нажата кнопка 1) с кнопкой ОК. Вторая, с надписью Button 2 (Кнопка 2), выводит сообщение Button 2 pushed (Нажата кнопка 2) с кнопками Yes и No и предложением завершить работу программы. В зависимости от того, какая кнопка будет нажата, будет выведено новое сообщение, указывающее, какая кнопка нажата, и соответственно будет или не будет выполнен выход из программы.

Ниже приведен пример скрипта:

Запуск этого скрипта генерирует GUI-приложение, показанное на рисунках с 5 по 11.

Рисунок 5. Пример виджета с кнопками
Рисунок 6. Нажата кнопка 1
Рисунок 7. Нажата кнопка 2
Рисунок 8. Нажата кнопка No
Рисунок 9. Подтверждение нажатия кнопки No
Рисунок 10. Нажата кнопка Yes
Рисунок 11. Подтверждение нажатия кнопки Yes

Это скрипт сложнее, чем предыдущие примеры, но разобрать его так же просто, как и остальные. Вначале создается каждая кнопка и ей присваивается соответствующий текст ( Button #1 или Button #2 ). Каждая кнопка связывается с командой или функцией. Соответствующие подпрограммы называются button1_sub и button2_sub :

При нажатии кнопки $button1 выполняется подпрограмма button1_sub . Внутри нее создается сообщение, отображающее текст Button 1 Pushed (Нажата кнопка 1) с единственной кнопкой OK. Поскольку с кнопкой ОК более не связано никаких функций, при ее нажатии сообщение закрывается, и фокус возвращается к главному окну.

Эта подпрограмма похожа на предыдущую, за исключением того, что она содержит две кнопки Yes и No. Когда пользователь нажимает кнопку, появляется новое сообщение, указывающее, какая кнопка была нажата. Затем отображается другое сообщение, указывающее, будет ли закрыта программа.

Надпись

Надпись – это виджет с неизменяемым текстом. Надписи можно размещать перед текстовыми полями и полями ввода. Создайте скрипт следующего содержания:

Запуск этого скрипта и ввод текста генерирует GUI-приложение, показанное на рисунке 12.

Рисунок 12. Пример виджета с надписью

Первая строка создает надпись с текстом What’s your name? (Как вас зовут?):

Чтобы расположить надпись слева от поля ввода, укажите для метода pack выравнивание по левой стороне. Как и в предыдущих примерах, поле ввода создается с черным фоном и белым текстом. Чтобы расположить надпись справа от поля ввода, укажите для метода pack выравнивание по правой стороне.

Собираем все вместе

Теперь, когда мы изучили несколько типов виджетов, давайте соберем их вместе в один скрипт.

Запуск этого скрипта и ввод текста генерирует GUI-приложение, показанное на рисунке 13.

Рисунок 13. Сводный пример

Давайте разберем этот скрипт так же, как другие примеры. Сначала мы создаем основной фрейм и три фрейма внутри него. Эти фреймы содержат остальные виджеты и задают структуру интерфейса.

Затем добавляем надписи: одну в верхнем фрейме, другую в левом фрейме.

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

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

Также создаем текстовое поле, чтобы пользователь мог скопировать текст из поля ввода и при желании отредактировать его.

Ниже приведены подпрограммы для очистки поля и копирования.

Функция clear_entry удаляет весь текст, начиная с позиции 0.0 (строка 0 символ 0) до конца текстового поля. Функция copy_entry запрашивает текст в поле ввода и вставляет его в текстовое поле.

Заключение

Введение в использование Perl с модулем Perl/Tk в среде AIX будет полезно разработчикам, администраторам, а также клиентам и конечным пользователям. Вы можете превратить сложный для восприятия скрипт в профессионально оформленное приложение с графическим интерфейсом. Чтобы научиться работать с виджетами, потребуются некоторые усилия, но когда вы освоитесь, результат оправдает затраты.

Ресурсы для скачивания

Похожие темы

  • Оригинал статьи (EN).
  • Perl: здесь можно скачать последнюю версию.
  • «Визуализация данных при помощи Perl/Tk» (developerWorks, август 2003 г.; EN) – статья содержит дополнительные примеры использования модуля Perl/Tk.
  • ActivePerl – это бесплатный и готовый к использованию дистрибутив Perl для Windows, Mac, OS X, Linux, Solaris, AIX и HP-UX.
  • Раздел AIX и UNIX® сайта developerWorks содержит множество информации, связанной со всеми аспектами системного администрирования систем AIX и расширения ваших знаний о UNIX.
  • Популярные материалы (EN): познакомьтесь с материалами о AIX и UNIX, которые сочли интересными другие пользователи.
  • В библиотеке AIX и UNIX содержится информация по темам:(EN)
    • Системное администрирование
    • Разработка приложений
    • Производительность
    • Портирование
    • Безопасность
    • Советы
    • Инструменты и утилиты
    • Технология Java™
    • Linux®
    • Open source
  • Подкасты IBM: настройте и получайте материалы от технических экспертов IBM.

Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

Ещё один блог сисадмина

воскресенье, 10 ноября 2013 г.

Шаблоны проектирования в Perl

Перевод статьи: Perl Design Patterns
Автор: Фил Кроу (Phil Crow)

В 1995 году была опубликована книга «Шаблоны проектирования». В последующие годы она оказала значительное влияние на способ написания программ множеством разработчиков. В этой серии статей я рассмотрю книгу «Шаблоны проектирования» (так же называемую «книгой банды четырёх») и её философию применительно к Perl. Поскольку Perl — это объектно-ориентированный язык, то в нём можно напрямую применять примеры из книги банды четырёх. Однако, многие из проблем, которые пытается решить банда четырёх, лучше решаются способом, характерным для Perl, с использованием возможностей, не доступных разработчикам на Java или C++ и ориентированных исключительно на использование объектов. Даже в тех случаях, когда разработчики на других языках желают воспользоваться процедурными методиками, они не могут воспользоваться чрезвычайно мощной встроенной поддержкой шаблонов, которая имеется, например, в Perl.

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

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

Перед реализацией объектов необходимо понимать основы объектной системы Perl. Вы можете изучить её в печатных источниках, например, в Книге рецептов Perl Тома Кристиансена (Tom Christiansen) и Нэта Торкингтона (Nat Torkington) или по книге Объектно-ориентированный Perl Дэмиана Конуэя (Damian Conway). Но простейший способ изучить основы — это perldoc perltoot.

В качестве обоснования моего подхода позвольте мне начать с небольшой объектно-ориентированной философии. Вот два моих основных принципа объектов:

  1. Объекты хороши, когда данные и методы тесно связаны.
  2. В большинстве других случаев объекты — это излишество.

Позвольте мне кратко обосновать эти принципы.

Объекты хороши, когда данные и методы тесно связаны.

Если вы работаете в компании по прокату машин (как я), имеет смысл представить в виде объекта договор проката. Данные по договору сильно связаны с методами, необходимыми для операций с ним. Для подсчёта платы за прокат вы можете использовать различные коэффициенты и складывать их вместе и т.п. Это подходящий случай для того, чтобы воспользоваться объектом (или скорее — совокупностью нескольких объектов).

В большинстве других случаев объекты — это излишество.

Рассмотрим несколько примеров из других языков. В Java есть класс java.lang.Math. Он содержит, например, функции sine и cosine. Он содержит только методы класса и пару констант класса. Их не стоило насильно вписывать в объектно-ориентированные рамки, поскольку не существует объектов Math. Лучше было бы поместить эти функции в ядро, полностью удалив или сделать простые не объектно-ориентированные функции. Последняя возможность в Java недоступна в принципе.

Или обратимся к стандартной библиотеке шаблонов C++. Для того, чтобы сделать C++ обратно совместимым с C и сохранить возможность строгой статической проверки типов, необходим целая система шаблонов. То, что должно являться частью самого языкового ядра, существует в виде неуклюжих объектно-ориентированных конструкций. Почему бы в язык для начала просто не ввести более удобный тип для массива? Затем можно было бы заняться такими общеизвестными структурами данных, как стеки, очереди, двусвязные очереди и многими другими структурами данных, которые изучают в школе.

В частности, я не поддерживаю один из подходов банды четырёх: превращение идеи в полномасштабный класс объектов. Я предпочитаю подход Perl — внедрение наиболее важных концепций в ядро языка. Поскольку я предпочитаю подход Perl, я не буду показывать, как превратить в объект то, что гораздо проще представить в виде хэша без методов или в виде простых функций без класса. Я использую подход, обратный подходу банды четырёх: реализую полномасштабные шаблонные классы с использованием более простых концепций Perl.

Шаблоны в этой первой статье главным образом основаны на использовании встроенных возможностей Perl. В последующих статьях я рассмотрю другие группы шаблонов. Теперь, когда я объяснил, что я буду делать, можно приступать.

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

Банда четырёх предполагает использование описанного выше приёма: превратить концепцию в объект. Это означает, что вы должны сделать итератор объектом. Каждый класс объекта, который нужно обходить должен иметь метод, возвращающий объект-итератор. Этот объект должен быть единообразным. Например, рассмотрим следующий код, в котором итератор используется для обхода ключей хэша в Java.
Объект HashMap содержит элементы, которые можно обойти — это его ключи. Вы можете запросить их с помощью метода, возвращающего множество ключей — keySet. Это множество предоставляет вам объект-итератор Iterator, если вызвать его метод iterator. Iterator отвечает на запрос hasNext истиной, если ещё остались элементы для обхода и ложью, если элементы закончились. Метод next возвращает следующий объект из последовательности, которой управляет Iterator. С помощью этого объекта key, HashMap возвращает следующее значение в ответ на вызов get(key). Это аккуратно и чисто в полностью объектно-ориентированном языке с ограниченными операторами и встроенными типами. И это точный пример шаблона Итератор от банды четырёх.

В Perl любой встроенный или пользовательский объект, который можно обойти, имеет метод, возвращающий упорядоченный список элементов для обхода. Чтобы обойти список, его нужно просто поместить внутрь скобок цикла foreach. Поэтому пример выше для обхода хэша в Perl будет выглядеть следующим образом:
Я мог бы реализовать этот шаблон в точном соответствии с диаграммой банды четырёх, но в Perl для этого есть более подходящий способ. В Perl 6 появится возможность вернуть «ленивый» список, элементы которого будут вычисляться по мере необходимости, так что приведённый выше код станет более эффективным, чем сейчас. В Perl 5 при вызове keys список ключей создаётся целиком. В будущем список ключей будет создаваться при необходимости, в большинстве случаев экономя память и время, если цикл закончился досрочно. *

Встроенная поддержка итераций в ядре языка свидетельствует о качестве дизайна Perl. Вместо неуклюжего механизма без поддержки ядром языка, как в Java и C++ (который, однако, есть в стандартной библиотеке шаблонов), Perl содержит этот шаблон в ядре языка. Как было сказано во введении, это принцип Perl:

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

Пример выше использует ядро языка. Чтобы убедиться, что foreach полностью реализует шаблон итератор, даже для пользовательских модулей, рассмотрим пример из CPAN: XML::DOM. DOM для XML был определён Java-программистами. Один из методов, который вы можете вызвать для обработки DOM-документа, это getElementsByTagName. В спецификации DOM он возвращает NodeList, являющийся коллекцией Java. Однако, NodeList работает подобно Set в Java-коде из примера выше. Вы должны попросить его вернуть Итератор, а затем обойти его.

Если Perl-программист реализует DOM, он безусловно сделает так, чтобы getElementsByTagName возвращал обычный список Perl. Чтобы обойти список, он скажет что-то вроде:
Это разительно отличается от излишне многословного варианта Java:
Одно из достоинств Perl заключается в возможности эффективно совмещать процедурный и объектно-ориентированный подходы с использованием возможностей ядра. На самом деле то, что банда четырёх предлагает реализовывать шаблон при помощи объектов и эти объекты нужны только в языках вроде Java, совершенно не означает, что программисты на Perl должны игнорировать не объектные возможности Perl.

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

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

При обычной работе декоратор оборачивает объект, реализуя тот же интерфейс, что и обёрнутый объект. Например, предположим я добавил декоратор сжатия к объекту для записи файлов. Вызывающий код передаёт объект для записи файла конструктору декоратора и осуществляет запись в декоратор. Метод записи из декоратора сначала сжимает данные, а затем вызывает метод записи из обёрнутого объекта, осуществляющего запись. Любой другой тип объекта для записи файлов может быть обёрнут тем же декоратором, если все объекты для записи файлов реализуют один и тот же интерфейс. Декораторы можно выстраивать в цепочку. Текст может быть преобразован из ASCII в Unicode одним декоратором, а сжат другим. Порядок декораторов в цепочке имеет значение.

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

Ввод-вывод — наиболее частое применение декораторов. Perl позволяет реализовать декорацию ввода-вывода напрямую. Рассмотрим пример, приведённый выше: сжатие в процессе записи. Есть два способа сделать это.

Использование оболочки и её инструментов

При открытии файла на запись в Perl можно воспользоваться средствами декорации из оболочки. Вот код примера рассмотренного выше:
Теперь всё, что я пишу, пропускается через gzip перед тем, как попасть в output.gz. Этот способ пригоден до тех пор (1), пока вам хочется использовать оболочку, что иногда может оказаться не безопасным; и (2) в оболочке есть инструменты для того, что вам нужно сделать. Также внушает беспокойство вопрос об эффективности. Операционная система порождает новый процесс на шаге gzip. Создание процесса — это одна из самых медленных операций операционной системы, не являющейся операцией ввода-вывода.

Если нужно больше контроля над процессом обработки данных, тогда можно задекорировать его самостоятельно, при помощи механизма Perl под названием tie. Он быстрее, проще в использовании и мощнее в Perl 6, но работает и в Perl 5. Он работает с использованием объектно-ориентированной системы Perl; обратитесь к странице perltie за более подробной информацией.

Предположим, что нужно предварить отметкой времени каждую строку, выводимую в дескриптор. Вот связанный (tied) класс, который это делает.
Это минимальный класс, в действительности может понадобиться дополнительный код, чтобы сделать декоратор более завершённым. Например, в коде выше не осуществляется проверка возможности записи в дескриптор, не проверяется, что он реализует PRINTF, поэтому вызов printf может завершиться ошибкой. Не стесняйтесь подумать о деталях. (Опять же, обратитесь к perldoc perltie за более подробной информацией.)

Вот несколько вещей, которые необходимо сделать. Конструктор связанного (tied) класса дескриптора файла называется TIEHANDLE. Его имя фиксировано и состоит из букв верхнего регистра, потому что Perl будет его вызывать. Это метод класса, поэтому его первый аргумент — имя класса. Другой аргумент — дескриптор, открытый на запись. Конструктор просто «благословляет» (bless) ссылку на дескриптор и возвращает её.

Метод PRINT принимает объект, сконструированный TIEHANDLE, и все аргументы, которые нужно напечатать. Он подсчитывает отметку времени и отправляет их вместе с исходными аргументами в дескриптор, используя настоящую функцию печати. Именно так работает декоратор. Декорированный объект позволяет печатать точно так же, как обычный дескриптор. Он выполняет небольшую работу, затем вызывает такой же метод из обёрнутого объекта.

Метод CLOSE закрывает дескриптор. Я использую наследование от Tie::StdHandle, чтобы получить этот метод и многие другие.

Поскольку я поместил AddTimeStamp.pm в каталог, входящий в последовательность поиска библиотек, я могу воспользоваться им таким образом:
После обычного открытия файла на запись я использую встроенную функцию для связывания дескриптора LOG с классом AddStamp под именем STAMPED_LOG. После этого я обращаюсь исключительно к STAMPED_LOG.

Если есть другой декоратор связывания, тогда можно передать связанный дескриптор ему. Единственный недостаток заключается в том, что Perl 5 работает со связанными объектами медленнее, чем с обычными. Ещё, по моему опыту, диски и сеть — это наиболее частые узкие места, поэтому не стоит обращать внимание на неэффективность использования памяти. В любом случае, если я ускорю скрипт на 90 процентов, я не сэкономлю много времени, потому что скрипт изначально работал не долго.

Такой подход работает для многих встроенных типов: скаляров, массивов, хэшей, как и для дескрипторов файлов. В документе perltie объясняется, как применять связывание к каждому из них.

Связывание великолепно, поскольку оно не требует, чтобы вызывающий код понимал, что происходит за кулисами. Это также справедливо и для декораторов банды четырёх, за одним понятным исключением: в Perl можно изменять поведение встроенных типов.

Одна из наиболее частых задач в Perl — это какое-либо преобразование списков. Возможно понадобится пропустить все элементы списка, начинающиеся с подчёркивания. Возможно потребуется отсортировать список или обратить порядок его элементов. Многие встроенные функции являются фильтрами списков. Они похожи на фильтры Unix, которые ожидают строки данных на стандартном потоке ввода, которые они каким-то образом преобразуют, перед тем как отправить результат на стандартный поток вывода. Как и в Unix, фильтры списков в Perl могут быть объединены в цепочку. Например, предположим, что нужен список всех подкаталогов в текущем каталоге в обратном алфавитном порядке. Вот одно из возможных решений:
В Perl 6 появился более понятный способ записи для этих операций, но при небольшом усилии можно научиться читать их и в Perl 5. Одна из интересных строк — шестая. Начните читать её справа (пользователи Unix воспримут это как обратный порядок). Сначала происходит чтение каталога. Поскольку map ожидает получить список, readdir возвращает список всех файлов в каталоге. map создаёт список с именем каждого файла, который является каталогом (или undef, если проверка -d не пройдена). sort упорядочивает список в порядке, подобном алфавитному, но использует вместо алфавита таблицу ASCII-кодов. reverse переставляет элементы списка в обратном порядке. Результат сохраняется в @files для последующей печати.

Можно очень легко создать собственный фильтр списков. Предположим, что нужно заменить уродливое использование map в примере выше (я считаю, что map всегда уродлив) на функцию специального назначения, вот так:
Новая подпрограмма dirs_only заменяет map из предыдущего примера, пропуская нежелательные элементы списка.

Теперь в sort явным образом прописана подпрограмма сравнения. Это позволяет избежать ошибочной мысли о том, что dirs_only — это подпрограмма сравнения. Поскольку я вписал сравнение, я решил извлечь пользу из сложившейся ситуации и сортирую более точно, игнорируя регистр символов.

Можно создавать любые фильтры списков, которые придутся вам по душе.

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

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

Мысль о повторном использовании объектов — это сущность шаблона «приспособленец». Благодаря Марку-Джейсону Доминусу (Mark-Jason Dominus), Perl заходит в этой идее дальше, чем предполагает банда четырёх. Кроме того, он сделал эту работу один раз и для всех. Ларри Уоллу (Larry Wall) нравится эта идея настолько сильно, что он продвигает её в ядро Perl 6 (речь идёт о продвижении самой концепции).

Для объектов, чьи экземпляры не важны (они постоянны или случайны), запрос нового объекта должен возвращать тот же объект, который уже был создан ранее, если это возможно.

Этот шаблон совершенно не подходит, если нужны раздельные экземпляры объектов. Но если они не нужны, тогда с помощью таких объектов можно сэкономить время и память.

Вот пример того, как это работает в Perl. Предположим, что я хочу предоставить класс die для игр вроде Монополии или Костей. Мой класс die может выглядеть следующим образом: (Предупреждение: Это надуманный пример, имеющий целью проиллюстрировать приём.)
На первый взгляд, этот класс похож на множество других классов. Он имеет конструктор под именем new. Конструктор сохраняет принятое значение в лексической переменной подпрограммы (так же известной как my-переменная), возвращая «благославлённую» ссылку на неё. Метод roll генерирует случайное число, умножает его на количество граней и возвращает результат.

Всё удивительное заключается в этих двух строчках:
Они используют выдающиеся возможности Perl. Вызов функции memoize изменяет таблицу функций вызывающего модуля таким образом, что new оказывается обёрнутой. Обёртка функции проверяет входящие аргументы (в данном случае — количество граней). Если обёртка до этого не встречала таких аргументов, она вызовет функцию, запрошенную пользователем, сохранит результат в кэш и вернёт его пользователю. На это потребуется больше времени и памяти, чем если бы этот модуль не использовался.

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

Единственное, о чём следует помнить — о том, что некоторые методы не выигрывают от применения этого приёма. Например, если вызвать memoize для roll, то она каждый раз будет возвращать одно и то же число, что не будет ожидаемым результатом.

Отметим, что Memoize может использоваться в случаях, где может и не быть объектов — на самом деле в его документации не предусматривается его использование в качестве фабрик объектов.

Мало того, что в языках подобных Java нет встроенных функций для кэширования результатов вызова методов, они вообще не позволяют талантливым пользователям реализовать такие функции. Марк-Джейсон Доминус (Mark-Jason Dominus) великолепно с этим справился, реализовав Memoize, но Ларри Уолл (Larry Wall) сделал большее, дав ему такую возможность. Представьте, что Java позволяет пользователю написать класс, манипулирующий таблицей символов вызывающего модуля во время работы. Мне кажется, что я уже слышу вопли ужаса. Конечно, такие приёмы могут привести к злоупотреблениям, но мы бы потеряли не много, поскольку мы всегда можем отказаться от дурного кода менее талантливых программистов, которые ошибаются при редактировании таблицы символов.

В Perl такие вещи вполне законны, но некоторые из них лучше оставить для модулей с сильным сообществом разработчиков. Это позволяет обычным пользователям получать преимущества от волшебства, не беспокоясь о том, чтобы заставить работать собственное волшебство. Memoize — это образец. Вместо создания собственных обёрток для вызовов и схемы кэширования, воспользуйтесь хорошо протестированной обёрткой, идущей в комплекте с Perl (и посмотрите свойство ‘is cached’ — кэшируется, чтобы сделать подобное с подпрограммами в Perl 6).


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

В шаблоне «приспособленец» мы узнали, что существуют некоторые ресурсы, которые являются общими. Банда четырёх выделяет особый случай, когда есть всего один ресурс, который должен быть общим для всех. Это шаблон «одиночка». Предположим, что этим ресурсом является хэш, который содержит параметры конфигурации. Кто угодно должен иметь возможность заглянуть в этот хэш, но он должен быть создан при запуске (и может быть пересоздан по некоторому сигналу).

В большинстве случаев можно просто воспользоваться Memoize. Мне это кажется наиболее разумным. (Смотрите выше раздел «приспособленец».) В этом случае каждый, кто хочет получить доступ к ресурсу, вызывает конструктор. Первое же обращение к конструктору повлечёт за собой создание объекта, который и будет возвращён. Последующие вызовы конструктора будут возвращать объект, созданный при первом вызове конструктора.

Есть много других способов достичь того же результата. Например, если вы предполагаете, что вызывающий код может передать неожиданные аргументы, тогда Memoize будет создавать множество экземпляров, по одному на каждый набор аргументов. В этом случае есть смысл воспользоваться модулями управления одиночек, например, такими как Cache::FastMemoryCache на CPAN. Вы также можете воспользоваться переменными в области видимости файла, назначая им значение в блоке BEGIN. Помните, что bless не может использоваться в методе. Вы могли бы написать так:
Этот пример демонстрирует прямолинейный способ, который позволяет избежать некоторых накладных расходов Memoize. В этом примере я не учитывал возможность создавать подклассы. Может быть я должен был бы это сделать, но шаблон утверждает, что одиночка всегда принадлежит лишь одному классу. Это основополагающее утверждение об одиночках:

«Может существовать только один одиночка.» **

Все четыре шаблона, рассмотренные в статье, используют встроенные возможности или стандартные модули. Итератор реализуется при помощи foreach. Декоратор реализуется при помощи перенаправления ввода-вывода Unix или при помощи связывания дескриптора файла. Для списков декораторы — это просто функции, которые получают и возвращают списки. Поэтому я мог бы назвать декораторы фильтрами. Приспособленцы — это общие объекты, которые легко реализуются при помощи модуля Memoize. Одиночки могут быть реализованы как приспособленцы или при помощи обычных объектов.

В следующий раз, если некоторые высокомерные объектно-ориентированные программисты заведут разговор о шаблонах, будьте уверены — вы знаете, как их использовать. Фактически, они встроены в ядро вашего языка (по крайней мере если подразумевать Perl). ***

В следующих статьях я рассмотрю шаблоны, основанные на контейнерах данных и ссылках на код.

Я написал эти статьи после прохождения курса банды четырёх от известной консалтинговой и тренинговой компании. Мои записки основаны на знаниях многих людей в сообществе Perl, включая Марка-Джейсона Доминуса (Mark-Jason Dominus), который продемонстрировал на YAPC 2002 свой талант обращения с итераторами в Perl. Хотя написанное тут принадлежит мне, меня вдохновили Доминус и многие другие члены сообщества Perl, в наибольшей степени — Ларри Уолл (Larry Wall), который встраивал шаблоны в сердце Perl в течение многих лет. Как раз за разом показывают эти шаблоны, Perl аккуратно и тщательно реализует принципы поощрения. Вместо добавления коллекций в виде исходных текстов модулей, как это сделано в Java и C++, в Perl есть только два вида коллекций: массивы и хэши. Оба входят в ядро языка. Я думаю, что величайшая сила Perl заключается в том, что сообщество может выбирать, что должно войти в ядро, а что должно быть вынесено из него. Perl 6 делает Perl лишь более конкурентноспособным в войне идей проектирования языков. ****

*) Так называемые «ленивые» списки имеются в Python и используются довольно часто. Например, при чтении строк из файла. Или при обходе диапазона целых чисел при помощи xrange. Или при переборе строк, возвращённых запросом к базе данных. Автор излишне зациклен на Perl и превозносит его подход чуть ли не как идеальный. Но из всего перечисленного Perl по умолчанию умеет «лениво» перебирать только строки файлов. Впрочем, при необходимости, реализовать ленивость в Perl 5 всё же можно — для этого можно воспользоваться операцией связывания, tie.

**) Тут я не смог пройти мимо, чтобы не процитировать фразу из сериала «Компьютерщики»: «Я — одинокий одиночка, идущий одинокой ночью по одинокой дороге. Один.»

***) На самом деле в этой статье шаблоны рассмотрены довольно поверхностно. Для полного понимания лучше всё же прочитать книжку, хоть она и довольно тяжела для восприятия. Впрочем, пользу от статьи тоже не стоит недооценивать.

****) Статья была написана в 2003 году, в разгар работы над Perl 6, когда ещё казалось, что у него есть будущее.

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

От редактора: Когда мы публиковали это произведение, нам ничего не было известно об его авторстве. Спасибо нашим читателям, благодаря им мы нашли фамилию автора оригинального текста (Стив Холзнер). Но по-прежнему остается неизвестным герой, который перевел его на русский язык. Если Вам известно что-нибудь именно об этом переводе (существуют другие), пожалуйста, Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript ! Сам же текст прислан Тихоном Тарнавским aka t.t.

Определения

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

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

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

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

Оператор qr/pattern/ ключи — imosx работает подобно регулярному выражению s/. /. /

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

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

файл 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) или for $elem (@mass) . Эти две строчки делают одно и то-же, но в первом случае запись короче, да и зачастую бывает удобно использовать переменную $_ , например, когда нужно выделить при помощи регулярного выражения определенные данные, пользуясь перебором массива(функция map):

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

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

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

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

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

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

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

Если $/ переопределить, то можно свободно пользоваться дескрипторами открытия файлов для просмотра многострочного текста( m/pattern/s ). Например когда открывается файл при помощи функции open F, " , то присваивая дескриптор 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 последовательности, для этого вызывается соответствующая подпрограмма:

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

g - заменить все одинаковые компоненты, а не один, как в отсутствии ключа g .
i - не учитывать регистр.
m - строка, в которой происходит поиск, состоит из множества строк.
s - строка, в которой происходит поиск, состоит из одной строки.
x - сложный шаблон, т.е. можно писать не в строчку, а для упрощения понимания разбивать шаблон на несколько строк, примеры об этом ниже.
o - компилировать шаблон один раз.

Допустим нужно сделать поисковик, который ходит по директориям на сервере, но некоторые директории типа /cgi-bin/ и т.п. индексировать нельзя. Объявляем переменную, которая будет содержать регулярное выражение, в данном случае перечисление или 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 .

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

одиночные символы

Правильнее проверить, что введенное пользователем слово "quit" не имеет со-седних слов, изменяющих смысл предложения. (Например, программа выполнит заведомо неверное действие, если вместо "quit" пользователь введет команду "Don't quit!".) Это можно сделать с помощью метасимволов ^ и $ . Заодно, что-бы сравнение было нечувствительно к разнице между прописными и заглавными буквами, используем модификатор i :

Кроме обычных символов perl определяет специальные символы. Они вводятся с помощью обратной косой черты (escape-последовательности) и также могут встречаться в регулярном выражении:

  • \077 - восьмеричный символ,
  • - символ BEL (звонок),
  • \с[ - управляющие символы (комбинация Ctrl + символ, в данном случае это управляющий символ ESC),
  • \d - соответствует цифре,
  • \D - соответствует любому символу, кроме цифры,
  • - символ escape (ESC),
  • - конец действия команд \L , \U и \Q ,
  • \f - символ прогона страницы (FF),
  • \1 - следующая литера становится строчной (lowercase),
  • \L - все последующие литеры становятся строчными вплоть до командй \Е,
  • \n - символ новой строки (LF, NL),
  • \Q - вплоть до команды все последующие метасимволы становятся обычными символами,
  • \r - символ перевода каретки (CR),
  • \s - соответствует любому из "пробельных символов" (пробел, вертикальная , или горизонтальная табуляция, символ новой строки и т. д.),
  • \S - любой символ, кроме "пробельного",
  • \t - символ горизонтальной табуляции (НТ, TAB),
  • \u - следующая литера становится заглавной (uppercase),
  • \U - все последующие литеры становятся заглавными вплоть до команды \E ,
  • \v - символ вертикальной табуляции (VT),
  • \w - алфавитно-цифровой символ (любая буква, цифра или символ подчеркивания),
  • \W - любой символ, кроме букв, цифр и символа подчеркивания,
  • \x1B - шестнадцатиричный символ.

Bat также можете "защитить" любой метасимвол, то есть заставить perl рассматривать его как обыкновенный символ, а не как команду, поставив перед метасимволом обратную косую черту \ . Обратите внимание на символы типа \w , \d и \s , которые соответствуют не одному, а любому символу из некоторой группы. Также заметьте, что один такой символ, указанный в шаблоне, соответствует ровно одному символу проверяемой строки. Поэтому для задания шаблона, соответствующего, например, слову из букв, цифр и символов подчеркивания, надо использовать конструкцию \w+ , как это сделано в следующем примере:

классы символов

Другой пример: с помощью шаблона [A-Za-z]+ (метасимвол + означает утверждение: "один или более таких символов") ищется и заменяется первое слово:

Если требуется задать минус как символ, входящий в класс символов, перед ним надо поставить обратную косую черту \- . Если сразу после открывающей квадратной скобки стоит символ ^ , то смысл меяется на противоположный. А именно, этот класс сопоставляется любому символу, кроме перечисленных в квадратных скобках. В следующем примере производится замена фрагмента текста, составленного не из букв и не из пробелов:

альтернативные шаблоны

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

В следующем примере метасимволы ^ и $ обозначают начало и конец строки и отделяются от набора альтернативных шаблонов с помощью скобок:

Альтернативные варианты перебираются слева направо. Как только найдена первая альтернатива, для которой выполняется совпадение с шаблоном, перебор прекращается. Участки шаблона, заключенные в круглые скобки, выполняют специальную роль при выполнении операций поиска и замены. Если символ \ находится в квадратных скобках, он интерпретируется как обычный символ. Поэтому если вы используете конструкцию шаблона вида [Tim|Tom|Tam] , то она будет эквивалентна классу символов [Tioam|] . Точно так же большинство других метасимволов и команд, специфичных для регулярных выражений - в частности, квантификаторы и мнимые символы, описанные в двух последующих разделах, - внутри квадратных скобок превращаются в обычные символы или escape-последовательности текстовых строк.

квантификаторы

Квантификаторы в регулярных выражениях

Квантификаторы указывают на то, что тот или иной шаблон в строке может повторяться определенное количество раз. Например, можно использовать квантификатор + для поиска мест неоднократного, повторения подряд латинской буквы е и их замены на одиночную букву е :

мнимые символы

Мнимые символы в регулярных выражениях

В perl имеются символы (метасимволы), которые соответствуют не какой-либо литере или литерам, а означают выполнение определенного условия (поэтому в английском языке их называют assertions, или утверждениями). Их можно рассматривать как мнимые символы нулевого размера, расположенные на границе между реальными символами в точке, соответствующей определенному условию:

  • ^ - начало строки текста,
  • $ - конец строки или позиция перед символом начала новой строки, распо-ложенного в конце,
  • \b - граница слова,
  • - отсутствие границы слова,
  • - "истинное" начало строки,
  • \Z - "истинный" конец строки или позиция перед символом начала новой строки, расположенного в "истинном" конце строки,
  • \z - истинный конец строки,
  • \G - граница, на которой остановился предыдущий глобальный поиск, выполняемый командой m/. / g,
  • (?= шаблон) - после этой точки есть фрагмент текста, который соответствует указанному регулярному выражению,
  • (?! шаблон) - после этой точки нет текста, который бы соответствовал указанному регулярному выражению,
  • (? - перед этой точкой есть фрагмент текста, соответствующий указанному регулярному выражению,
  • (? - перед этой точкой нет фрагмента текста, соответствующего указанному регулярному выражению.

Например, вот как выполнить поиск и замену слова, используя метасимволы границы слов:

perl считает границей слова точку, расположенную между \w и \W , независимо от того, в каком порядке следуют эти символы . В следующем примере выводится сообщение о том, что пользователь ввел слово "yes", при условии, что оно единственное, что ввел пользователь. Для этого шаблон включает мнимые символы начала и конца строки:

Приведенный выше пример требует комментария. Прежде всего, бросается в глаза наличие двух групп метасимволов для начала и конца строки. В большинстве случаев они означают одно и то же, так как обычно символы новой строки (то есть \n ), встречающиеся внутри текстового выражения, не рассматриваются как вложенные строки. Однако если для команды m/. / или s/. /. / указан модификатор m , то текстовое выражение будет рассматриваться как многострочный текст, в котором границами строк выступают символы новой строки \n . В случае многострочного текста метасимвол ^ сопоставляется с позицией после любого символа новой строки, а не только с началом текстового выражения. Точно также метасимвол $ - это позиция перед любым символом новой строки, расположенным внутри текстового выражения, а не обяательно конец текстового выражения или же позиция перед концевым символом \n . Однако метасимвол \A - начало текстового выражения, а метасимвол \Z - конец текстового выра-жения или позиция перед концевым символом \n , даже если в текстовом выражении имеются вложенные символы \n и при выполнении операции поиска или йены указан модификатор m . Метасимвол точка ( . ) соответствует любому символу, кроме символа новой строки \n . Независимо от того, задан ли модификатор m , она не будет сопоставляться ни c внутренними, ни с концевыми символами \n . Единственный способ заставить точку рассматривать \n как обычный символ - использовать модификатор s .

Отсюда понятна разница между метасимволами \Z и \z . Если в качестве текстового выражения используется результат чтения входного потока данных, то с большой вероятностью данное выражение заканчивается символом \n , за исключениeм того варианта, когда программа предусмотрительно "отщипнула" его с помощью функции chop или chomp . Метасимвол \Z игнорирует концевой символ \n если он случайно остался на месте, рассматривая обе ситуации как "конец строки". В отличие от него метасимвол \z оказывается более пунктуальным и рассматривает концевой символ \n как неотъемлемую часть проверяемого текстового выражения, если только пользователь не позаботился об удалении этого символа.

Отдельно следует остановиться на метасимволе \G . Он может указыватьсяв регулярном выражении только в том случае, если выполняется глобальный поиск (то есть если команда m/. / имеет модификатор g ). Метасимвол \G , указанный в шаблоне, соответствует точке, на котброй остановилась предыдущая операция поиска.

ссылки на найденный текст

Иногда нужно сослаться на подстроку текста, для которой получено совпадение с некоторой частью шаблона. Например, при обработке файла, HTML может потребоваться выделять фрагменты текста, ограниченные открывающими и закрывающими метками HTML (например, и ). В начале уже приводился пример, в котором выделялся текст, ограниченнуй метками HTML и . Следующий пример позволяет выделять текст, расположенный между любыми правильно закрытыми метками:

Вместо косой черты в качестве ограничителя шаблона использован другой символ. Это позволяет использовать символ косой черты внутри шаблона без предшествующей ему обратной косой черты. Каждому фрагменту шаблона, заключенному в круглые скобки, соответствует определенная внутренняя переменная. Переменные пронумерованы, так что на них можно ссылаться внутри шаблона, поставив перед номером обратную косую черту ( \1 , \2 , \3 . ). На значения переменных можно ссылаться внутри шаблона, как на обычный текст, поэтому соответствует , если открываю-щей меткой служит , и , если открывающей меткой служит . Эти же самые внутренние переменные можно использовать и вне шаблона, ссылаясь на них как на скаляры с именами $1 , $2 , $3 , . , $n :

Каждой паре скобок внутри шаблона после завершения операции поиска будет соответствовать скалярная переменная с соответствующим номером. Это можно 'использовать при выделении нужных для последующей работы фрагментов ана-лизируемой строки. В следующем примере мы изменяем порядок трех слов в тек-стовой строке с помощью команды s/. /. / :

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

Кроме переменных, ссылающихся на найденный текст, можно использовать специальные переменные perl.

Функции, использующие регулярные выражения

split

Если необходимо разделить данные из STDIN по нужному разделителю, то можно воспользоваться локализацией $/ :

Можно разделять данные из файла и так: что эквивалентно: После split можно ставить вместо запятой и стрелочку:

В функции сплит можно воспользоваться макисмальным квантификатором * , который в том числе и о символов, позволит разделить строку на символы, которых там нет(в силу того, что * это 0 и более символов), т.е. посимвольно:

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

other

Использование встроенных переменных

  • $' - подстрока, следующая за совпадением.
  • $& - совпадение с шаблоном поиска
  • $` - подстрока, расположенная перед совпадением
  • $^R - результат вычисления утверждения в теле шаблона
  • $n - n-ный фрагмент совпадения
  • \n - n-ный фрагмент совпадения вызываемый в самом шаблоне
  • $+ - фрагмент совпадения
  • $* - разрешает выполнять поиск в многострочных файлах
  • @- - спецмассив, который содержит начальную позицию найденного слова
  • @+ - массив, содержащий позицю последнего найденного слова


$& - совпадение с шаблоном поиска, при последней операции поиска или замены. В отличии от переменной $_ , эту переменную переопределять как вздумается нельзя.

$' подстрока за совпадением с шаблоном поиска, е также можно только читать.

$` - подстрока, расположенная перед совпадением, разрешается только е чтение.

$^R - результат вычисления утверждения в теле шаблона для последнего вычисления шаблона, если в нем идет счет или вызывается внешняя программа:

$+ - фрагмент совпадения в шаблоне, который в нем был последним в круглых скобках. Разрешается только чтение $+ .

$* - разрешает выполнять поиск в многострочных файлах, булева переменная, если она взведена в 1 , то символы шаблона поиска ^ и $ сопоставляются позициям перед и после внутренних символов новой строки, если , то от начала текста и до конца текста:

$n - n -ный фрагмент совпадения: \n - n -ный фрагмент совпадения вызываемый в самом шаблоне, например поиск гиперссылок: Например нужно занести в массив только цифры из строчки "12@#34@@#@@###34@@##67##@@#@#@34" : Регулярное выражение s/(#)\1+/$1/g; изпользует повторение переменной $1 (квантификатор + ) и если оно есть, то заменяет все подряд идущие # между цифрами на одну #, содержащуюся в $1 (переменная $1 существует, если часть шаблона или шаблон указать в круглых скобках).

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

Выражение берет 1-ю цифру и ищет е совпадения со всеми остальными, если есть, то говорит, что найдено и заканчивает работу. Регулярное выражение берет первое число при помощи (\d) и начинает его сравнивать со всеми остальными числами при помощи .*(?=\1). Если первое число в строке уникально, регулярное выражение начнет сопостовлять второе число со всеми восемью оставшимися числами. Если и второе число в строке уникально, то берется третье число и сравнивается со всеми остальными. И т.д., если совпадение было найдено, то регулярное выражение возвращает true и заканчивает свою работу, даже если в строке еще есть повторяющиеся числа. Чтобы можно было просмотреть все повторяющиеся числа, можно воспользоваться модификацией предыдущего кода:

Этот усовершенствованный код работает до тех пор, пока не будут найдены все совпадения, если таковые вообще есть.

В perl 5.6 вводятся переменные @- и @+ , комбинация которых может заменять переменные $` , $& , и $' . После совпадения шаблона переменная $-[0] содержит начало соответсвия текста шаблону, а переменная $+[0] содержит конец соответсвия текста шаблону. В начале поиска обе являются нулями. Это значит, что можно вычислить значения $` , $& , и $' :

Соответственное переменные $#- и $#- указывают размерность массивов @- и @+ .

Как работают регулярные выражения

Регулярные выражения, использующие квантификаторы, могут порождать процесс, который называется перебор с возвратом (backtracking). Чтобы произошло совпадение текста с шаблоном, надо построить соответствие между текстом и всем регулярным выражением, а не его частью. Начало шаблона может содержать квантификатор, который поначалу срабатывает, но впоследствии приводит к тому, что для части шаблона не хватает текста или возникает несоответствие между текстом и шаблоном. В таких случаях perl возвращается назад и начинает построение соответствия между текстом и шаблоном с самого начала, ограничивая "жадность" квантификатора (именно поэтому процесс и называется "перебор с возвратом"). Перечислим квантификаторы perl:

  • * - ноль или несколько совпадений,
  • + - одно или несколько совпадений,
  • ? - ноль совпадений или одно совпадение,
  • - ровно n совпадений,
  • - по крайней мере n совпадений,
  • - от n до m совпадений.

Например квантификатор + соответствует фразе "один или несколько" и является жадным. Расмотрим пошагово принцип перебора с возвратом на примере квантификатора + : a+ сразу в силу жадности совпадает с тремя а : но после aaa не следует строка " abc ", а следует " bc ". Поэтому результат - failed поэтому анализатор должен откатиться назад и вернуть с помощью a+ два a : (aa)abc т.е. на втором шаге шаблон найдет совпадение.

Рассмотрим пример работы еще одного жадного квантификатора * (ноль или несколько совпадений):

Сначала будет найдена вся строка abcdebfg в силу жадности .* , потом квантификатору нужно будет найти сравнение с буквой m , произойдет ошибка. Квантификатор .* отдаст одну букву и его содержимое будет уже amxdemx . На конце снова нет буквы m . Будет отдана еще одна буква и снова не будет найдено совпадение со всем шаблоном и наконец квантификатор .* будет содержать подстроку amxde , за которой уже стоит символ m . И поиск на этом и закончится не смотря на то, что в строке amxdemxg содержится не одна буква m . Потому и говорят, что квантификаторы обладают жадностью, т.е. находят максимально возможное совпадение.

Допустим нужно найти совпадение:

Квантификатор .* оставит текст " are ok??" , а вовсе не "? Thanks! I'm fine, you are ok??" . Если же поставить ограничитель ? , который вместе со знаком квантификатора означает максимально возможное совпадение

то переменная $uu будет содержать текст "? Thanks! I'm fine, you are ok??" .

Предположим нужно найти совпадения типа network workshop, т.е. перекрытия.

$1 сразу берет все слово в $u , но дальше идет еще один максимальный квантификатор (\w+) , которому тоже чего-то надо и он забирает из переменной \1 букву k (причем только одну): далее пошаговая работа regex выглядит примерно так: и в результате программа выдаст: Данный регексп не сработает, если шаблон найдет перекрытия workwork , а не work . Чтобы этого избежать, нужно сделать минимальным \1: /^(\w+?)(\w+) \2(\w+)$/

Квантификатор действует только на предшествующий ему элемент шаблона. Например, конструкция \d<2>[a-z]+ будет соответствовать последовательности из одной или нескольких строчных латинских букв, начинающейся с двух цифр, а не последовательности, составленной из чередующихся цифр и букв. Для выделения группы элементов, на которую действует квантификатор, используются круглые скобки: (\d<2>(a-z])+

Логические операции в регулярных выражениях

Поиск повторяющихся слов в регулярном выражении осуществляется при помощи т.н. обратных ссылок. Выше уже был приведен пример их использования для выбирания всех адресов рисунков с www.astronomynow.com:

(["']) - найти либо " либо ' либо ничего, т.к. src=http:// может быть без кавычек. Как только был надено что-либо из этих трех позиций, через минимальное количество символов(регулярное выражение (.*?) ) символов оно заносится в специальную переменную \1 , которая вне m/. / может быть вызвана как $1s/. /. / она вызывается в его левую половину как $1 ). Дальше после *.gif|*.jpg|*.bmp и т.д. должен обязательно идти хотя-бы один пробел \s+ , т.к. броузеры воспримут подстроку src=file.gifborder=0 как файл картинки с расширением gifborder=0 . Поэтому данное регулярное выражение вполне исправно работает, хотя оно было сделано для сайта, где в img src ставится полный адрес, т.е. начинающийся с http:// Для других сайтов придется выстраивать полные пути в ссылках используя base href , если есть или его url . Если нужно найти какое-то по счету совпадение шаблона в строке, то это реализуется примерно так: Каждое кратное совпадение Нужное Вам совпадение: Или каждое четное совпадение для нечетного нужно написать внутри grep : $n++ %2==1 Логические операции внутри регулярных выражений. Если нужно найти последнее совпадение, то можно воспользоваться отрицанием опережающей проверки (?!WHAT) : т.е. нийти какой-то PATTERN , при этом не должно найтись что-то еще( .* ) и PATTERN , т.е. результат - последнее совпадение;

допустим нужно найти двойку, перед которой не стоит 3 или пробел:

используется условие по отрицанию, A(?!B) : найти А , перед которым не находится В . Чтобы найти двойку, за которой стоит 3 или пробле( \s ), то можно воспользоваться:

где используется ^ , [^3\s] , который значит следущее: в класс символов, которые нужно найти, не входят 3 и пробел, или другими словами найти все кроме 3 и \s .

Допустим существует HTML-документ, в котором произвольное число вложенных таблиц [& lt;table>.*

]. Требуется "вырезать" по очереди самые вложенные таблицы (не содержащие внутри [

.*

]), и, соответственно, выводить. И так - рекурсивно до конца вырезать изнутри всю таблицу. Ниже представлена программа, реализующая эту задачу при помощи логического оператора (. ) :

Продолжаем рассматривать логические операторы в регулярных выражениях на опретаорах типа OR, AND или NOT.

Регексп истиннен, если /AM|BMA/ или /AM/ || /BMA/ и если есть перекрытие типа /BMAM/ . Так-же и /AM/ && /BMA/ :

Выражение истинно если /AM/ и /BMA/ совпадают при перекрытии которое не разрешено: Выражение истинно, если шаблон /ABC/ не совпадает: или Выражение истинно, если ABC не совпадает, а VBN совпадает: Несовпадение можно проверить несколькими способами: Для обязательного совпадения в двух шаблонах: Хотя бы в одном

Регулярные выражения - основа работы с операторами m/. / и s/. /. / , так как они передаются последним в качестве аргументов. Разберемся, как устроено регулярное выражение \b([A-Za-z)+)\b , осуществляющее поиск отдельных слов в строке:

Выражение \b([A-Za-z]+)\b включает в себя группирующие метасимволы ( и ) , метасимвол границы слова \b , класс всех латинских букв [A-Za-z] (он объединяет заглавные и строчные буквы) и квантификатор +, который указывает на то, что требуется найти один или несколько символов рассматриваемого класса. Поскольку регулярные выражения, как это было в предыдущем примере, могут быть очень сложными, разберем их по частям. В общем случае регулярное выражение состоит из следующих компонентов:

Совпадение с любым символом

В perl имеется еще один мощный символ - а именно, точка (.) . В шаблоне он соответствует любому знаку, кроме символа новой строки. Например, следующая команда заменяет в строке все символы на звездочки (использован модификатор g , обеспечивающий глобальную замену):

А что делать, если требуется проверить совпадение именно с точкой? Символы вроде точки (конкретно, \|()[<^$*+?. ), играющие в регулярном выражении осббую роль) называются, как уже было сказано выше, метасимволами, и если вы хотите, чтобы они внутри шаблона интерпретировались как обычные символы, метасимволу должна предшествовать обратная косая черта. Точно так же обратная косая черта предшествует символу, используемому в качестве ограничителя для команды m/. / , s/. /. / или tr/. /. / , если он встречается внутри шаблона и не должен рассматриваться как ограничитель. Рассмотрим пример:

Если нужно найти самый короткий текстовый фрагмент /QQ(.*?)FF/ в "QQ ff QQ ff FF" , однако оно найдет "ff QQ ff" . Шаблон всегда находит левую строку минимальной длины, которая соответствует всему шаблону, т.е. это вся строка в этом примере. Для правильного шаблона нужно воспользоваться логическими операторами в регулярных выражениях: /QQ((?:(?!QQ).)*)FF/ , т.е. сначала QQ , потом не QQ , потом FF .

Конструкции (? и (? работают только с шаблонами, соответствующими фиксированному числу символов. Иными словами, в шаблонах, указываемых для (? и (? , не должно быть квантификаторов.

Эти условия полезны, если нужно проверить, что перед определенным фрагментом текста или после него находится нужная строка, однако ее не требуется включать в результат поиска. Это бывает необходимо, если в коде используются спе-циальные переменные $& (фрагмент, для которого найдено соответствие между текстом и регулярным выражением), $` (текст, предшествующий найденному фрагменту) и $' (текст, следующий за найденным фрагментом). Более гибким представляется применение нумерованных переменных $1 , $2 , $3 , . в которые заносятся отдельные части найденного фрагмента.

В следующем примере ищется слово, за которым следует пробел, но сам пробел не включается в результат поиска:

Того же результата можно добиться, если заключить в круглые скобки интересу-ющую нас часть шаблона и затем использовать ее как переменную $1 :

Следует четко понимать, что вы имеете в виду, когда используете то или иное условие. Рассмотрим следующий пример:

Вопреки нашим ожиданиям, perl напечатает: Tom is without Mary! Это произойдет по следующей причине. Пробуя различные начальные точки входной строки, от которой начинается сопоставление шаблона и текста, pеr1 рано или поздно доберется до позиции, расположенной прямо перед именем " Tom ". Условие (?!Маry\+) требует, чтобы после текущей точки не находился текст * Маry+ ", и это условие для рассматриваемой точки будет выполнено. Далее, perl последовательно проверяет, что после текущей точки следуют буквы "Т", "o" и "m", и это требование также в силе (после проверки условия (?!Маry\+) текущая точка остается на месте). Тем самым найдено соответствие между подстрокой "Тоm" и шаблоном, поэтому команда поиска возвращает значение истина.

Регулярное выражение (?!Mary\+). Tom , резервирующее четыре символа под текст " Маry+ ", для приведенного выше случая выведет то, что требовалось, но выдаст ошибочный ответ, если перед именем "Тоm" нет четырех символов:

Наконец, если более точно сформулировать, чего требуется, получится нужный результат: Вспомнить и написать про строчку вида ; perldoc perlop [0-9.]

В perl имеется несколько модификаторов, используемых с командами m/. / и s/. /. / :

  • i - игнорирует различие между заглавными и строчными буквами.
  • s - метасимволу "точка" разрешено соответствовать символам \n .
  • m - разрешает метасимволам ^ и $ привязываться к промежуточным символам \n , имеющимся в тексте. Не влияет на работу метасимволов , \Z и \z .
  • х - игнорирует "пробельные символы" в шаблоне (имеются в виду "истинные" пробелы, а не метасимволы \s и пробелы, созданные через escape-последовательности). Разрешает использовать внутри шаблона комментарии.
  • g - выполняет глобальный поиск и глобальную замену.
  • с - после того как в скалярном контексте при поиске с модификатором g не удалось найти очередное совпадение, не позволяет сбрасывать текущую позицию поиска. Работает только для команды m/. / и только вместе с модификатором g .
  • о - запрещает повторную компиляцию шаблона при каждом обращении к данному оператору поиска или замены, пользователь, однако, должен гарантировать, что шаблон не меняется между вызовами данного фрагмента кода.
  • е - показывает, что правый аргумент команды s/. /. / - это фрагменты выполняемого кода. В качестве текста для подстановки будет использовано возвращаемое значение - возможно, после процесса интерполяции.
  • ee - показывает, что правый аргумент команды s/. /. / - это строковое выражение, которое надо вычислить и выполнить как фрагмент кода (через функцию eval ). В качестве текста для подстановки используется возвращаемое значение - возможно, после процесса интерполяции

До сих пор мы рассматривали регулярные выражения, используемые в качестве шаблонов для команд m/. / и s/. /. / , и не особо интересовались, как работают эти команды. Настало время восполнить пробелы.

Команда m/. / ищет текст по заданному шаблону. Ее работа и возвращаемое значение сильно зависят от того, в скалярном или списковом контексте она используется и имеется ли модификатор g (глобальный поиск).

Команда s/. /. / ищет прототип, соответствующий шаблону, и, если поиск оказывается успешным, заменяет его на новый текст. Без модификатора замена производится только для первого найденного совпадения, с модификатором g выполняются замены для всех, совпадений во входном тексте. Команда возвращает в качестве результата число успешных замен или пустую строку (условие ложь false), если ни одной замены сделано не было. В качестве анализируемого текста используется $_ (режим по умолчанию) или выражение, присоединенное к шаблону с помощью оператора =

. В случае поиска (команда m/. / ) конструкция, расположенная слева от операторов =

, может и не быть переменной. В случае замены (команда s/. /. / ) в левой части должна стоять скалярная переменная, или элемент массива, или элемент хэша, или же команда присвоения одному из указанных объектов.

Вместо косой черты в качестве ограничителя для аргументов команд m/. / и s/. /. / можно использовать любой символ, за исключением "пробельного символа", буквы или цифры. Например, в этом качестве можно использовать символ комментария, который будет работать как ограничитель:

В качестве ограничителей не стоит использовать вопросительный знак и апостроф (одинарную кавычку) - шаблоны, с такими ограничителями обрабатываются специалиным образом. Если команда m/. / использует символ косой черты в качестве разделителя, то букву m можно опустить:

Если в качестве ограничителя для команды m/. / используется вопросительный знак, то букву m также можно опустить. Однако шаблоны, ограниченные символом ? , в случае поиска работают особым образом (независимо от наличия или отсутствия начальной m ). А именно, они ведут себя как триггеры, которые срабатывают один раз и потом выдают состояние ложь (false), пока их не взведут снова, вызвав функцию reset (она очищает статус блокировки сразу всех конструкций . , локальных для данного пакета). Например, следующий фрагмент сценария проверяет, есть ли в файле пустые строки:

Диагностическое сообщение будет напечатано только один раз, даже если в файле присутствует несколько пустых строк. Команда поиска с вопросительным знаком относится к подозрительным командам, а потому может не войти в новые версии perl. 1 В качестве ограничителей можно также использовать различные (парные) койструкции скобок:

В случае команды s/. /. / и использования скобок как ограничителей для первого аргумента, ограничители второго аргумента могут выбираться независимо:

Предварительная обработка регулярных выражений

Аргументами команд m/. / и s/. /. / являются регулярные выражения, которые перед началом работы интерполируются подобно строкам, заключенным в двойные кавычки В отличие от текстовых строк, для шаблона не выполняется интерполяция имен типа $) , $| и одиночного $ - perl считает, что такие конструкции соответствуют метасимволу конца строки, а не специальной переменной. Если же в результате интерполяции шаблон поиска оказался пустой строкой, perl использует последний шаблон, который применялся им для поиска или замены.

Если вы не хотите, чтобы perl выполнял интерполяцию регулярного выражения, в качестве ограничителя надо использовать апостроф (одиночную кавычку), тогда шаблон будет вести себя, как текстовая строка, заключенная в апострофы. Однако, например, в случае команды замены s/. /. / с модификатором е или ее (их работа описывается чуть дальше) для второго аргумента будет выполняться интерполяция даже в том случае, если он заключен в апострофы.

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

Команда замены s/. /. / использует регулярное выражение, указанное в качестве второго аргумента, для замены текста. Поскольку оно обрабатывается (интерполируется) после того, как выполнена очередная операция поиска, в нем можно, в частности, использовать временные переменные, созданные на этапе поиска. В следующем примере мы последовательно заменим местами пары слов, заданных во входном тексте, оставив между ними по одному пробелу:

Однако perl допускает и более сложные способы определения заменяющего текста. Так, если для команды s/. /. / указать модификатор е , то в качестве второго аргумента надо указать код, который необходимо выполнить (например, вызвать функцию). Полученное выражение будет использованокак текст для подстановки. При этом после вычисления текстового значения, но пер д его подстановкой будет выполнен процесс интерполяции, аналогичный процессу интерполяции текстовых строк, заключенных в двойные кавычки. Еще более сложная схема реализуется, если задан модификатор ее . В этом слу-чае второй аргумент команды s/. /. / - это строковое выражение, которое сперва надо вычислить (то есть интерполировать), затем выполнить в качестве кода (вызвав встроенную функцию eval ) и только после второй интерполяции полученный результат подставляется вместо найденного текста.

Работа команды m/. / в режиме однократного поиска В скалярном контексте и без модификатора g команда m/. / возвращает логическое значение - целое число 1 (истина (true)), если поиск оказался успешным, и пустую строку "" (ложь (false)), если нужный фрагмент текста найти не удалось. Если внутри шаблона имеются группы элементов, заключенные в круглые скобки, то после операции поиска создаются нумерованные переменные $1 , $2 , . в которых содержится текст, соответствующий круглым скобкам. В частности, если весь шаблон заключить в круглые скобки, то в случае успешного поиска переменная $1 будет содержать текст, соотнесенный с шаблоном. После успешного поиска можно также использовать специальные переменные $& , $' , $' и $+

Если вы используете команду m/. / в списковом контексте, то возвращаемое значение сильно зависит от того, есть ли группы из круглых скобок в вашем шаблоне. Если они есть (то есть если создаются нумерованные переменные), то после успешного поиска в качестве результата будет получен список, составленный из нумерованных переменных ( $1 , $2 . ):

В отличие от ранних версий, perl 5 присваивает значения нумерованным переменным, даже если команда поиска работает в списковом контексте:

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

Обратите внимание на разницу между пустым и неопределенным списками.

Работа команды m/. / в режиме глобального поиска

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

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

В случае неудачного поиска, как и в предыдущих вариантах, возвращается пустой список. В скалярном контексте и с модификатором g комaндa m/. / ведет себя сивершенно особым образом. Специальная переменная $_ или переменная, стоящая слева от оператора =

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

Состoяние (точнее, позиция) поиска сохраняется даже в случае перехода к следующему оператору поиска, имеющему модификатор g . Неудачный поиск сбрасывает значение в исходное состояние, если только для команды m/. / не указан модификатор с (то есть команда должна иметь вид m/. / gc ). Изменение текстового буфера, для которого выполняется поиск, также сбрасывает позицию поиска в исходное состояние. В следующем примере из текстовой строки последовательно извлекаются и выводятся пары имя/значение до тех пор, пока строка не закончится:

Позиция, на которой остановился поиск, может быть прочитана и даже переустановлена с помощью встроенной функции perl pos . В шаблоне на текущую позицию поиска можно ссылаться с помощью метасимвола \G . В следующем примере из строки последовательно извлекаются буквы p , o и q и выводится текущая позиция поиска:

В документации perl приводится основанный на этом механизме интересный пример последовательного лексического разбора текста. В нем каждая последующая команда поиска очередной лексической единицы начинает выполнятьсяс того места, где завершила свою работу предыдущая. Советую внимательно разобраться с этим примером (страница руководства perlop , раздел " Regexp Quote-Uke Operators ", описание команды m/PATTERN/ ), если вы хотите расширить доступный вам инструментарий perl!

Замена строк с помощью команды tr/. /. /

Кроме команд m/. / и s/. /. / строки можно обрабатывать с помощью команды tr/. /. / (она же - команда у/. /. / ):

В отличие от m/. / и s/. /. / , эта команда не использует шаблоны и регулярные выражения, а выполняет посимвольную замену, подставляя в текст вместо литер из первого списка соответствующие им литеры из второго списка. Например, в следующем случае производится замена литер " i " на " о ": $text = "My name is Tim."; $text =

tr/i/o/; print $text; My name is Tom.

В качестве списков используются идущие друг за другом символы, не разделяемые запятыми (то есть это скорее строки, чем списки). В отличие от шаблонов команд m/. / и s/. /. / , аргументы команды tr/. /. / не интерполируются (то есть подстановки значений вместо имен переменных не происходит), хотя escape-последовательности, указанные внутри аргументов, обрабатываются правильно. Подобно m/. / и s/. /. / , команда tr/. /. / пo умолчанию работает с переменной $_ :

В качестве списков можно указывать диапазоны символов - как, например в следующем фрагменте кода, заменяющем строчные буквы на заглавные: $text = "Here is the text."; $text =

tr/a-z/A-Z/; print $text; HERE IS THE TEXT.

Как и в случае m/. / u s/. /. / , команда tr/. /. / не требует использовать именно знаки косой черты в качестве ограничителей. Можно использовать практически любой символ, отличный от "пробельных", букв и цифр, а также парные скобочные конструкции.

Команда tr/. /. / возвращает число успешных замен. В частности, если не было сделано никаких замен, она возвращает число ноль. Это позволяет, например, подсчитать с помощью команды tr/. /. / количество вхождений буквы х в строку $text , не меняя содержимого этой переменной: $text = "Here is the text."; $xcount = ($text =

tr/x/x/); print $xcount; 1 Если у команды tr/. /. / нет модификаторов (см. далее раздел "Модификаторы команды tr/. /. / "), то ее аргументы при обычных условиях должны быть одинаковой длины. Если второй аргумент длиннее первого, то он усекается до длины первого аргумента - так, команда tr/abc/0-9/ эквивалентна команде tr/abc/012/ . Если первый аргумент длиннее второго и второй не пуст, то для второго аргумента необходимое число раз повторяется его последний символ - так, команда tr/O-9/abc/ эквивалентна команде tr/0123456789/abcccccccc/ . Если же второй, аргумент пуст, то команда tr/. /. / подставляет вместо него первый аргумент.

Как легко заметить, если второй аргумент пуст, то (при отсутствии модификаторов) команда tr/. /. / не производит никаких действий, а возвращаемое ею значение равно числу совпадений между первым аргументом и обрабатываемым текстом. Например, следующая команда подсчитывает количество цифр в строке:

Команда tr/. /. / работает без рекурсии, просто последовательно заменяет символы входного текста. Например, для замены заглавных букв на строчные, и на-оборот, достаточно выполнить команду:

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

Модификаторы команды tr/. /. /

Команда tr/. /. / допускает использование следующих модификаторов:

  • d - удаляет непарные символы, не выравнивая аргументы по длине.
  • с - в качестве первого аргумента использует полный список из 256 символов за вычетом указанных в списке символов.
  • s - удаляет образовавшиеся в результате замены повторяющиеся символы.

Если указан модификатор d , a первый аргумент команды длиннее второго, то все символы из первого списка, не имеющие соответствия со вторым списком, удаляются из обрабатываемого текста. Пример: удаляем строчные латинские буквы и заменяем пробелы на слэши:

Наличие модификатора d - единственный случай, когда первый и второй аргументы не выравниваются друг относительно друга, В остальных вариантах второй аргумент либо усекается, либо последний символ в нем повторяется до тех пор, пока аргументы не сравняются, либо, если второй аргумент пуст, вместо Второго аргумента берется копия первого.

Если указан модификатор с , то в качестве первого аргумента рассматриваются все символы, кроме указанных. Например, заменим на звездочки все символы, кроме строчных латинских букв:

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

Без модификатора s результат был бы другим: Примеры:
1. Заменить множественные пробелы и нетекстовые символы на одиночные пробелы: 2. Сократить удвоенные, утроенные и т.д. буквы; 3. Пересчитать количество небуквенных символов: 4. Обнулить восьмой бит символов, удалить нетекстовые символы: 5. Заменить нетекстовые и 8-битные символы на одиночный пробел: Поиск отдельных слов

Чтобы выделить слово, можно использовать метасимвол \S соответствующий символам, отличным от "пробельных":

Однако метасимвол \S соответствует также и символам, обычно не используемым для идентификаторов. Чтобы отобрать слова, составленные из латинских букв, цифр и символов подчеркивания, нужно использовать метасимвол \w : Если требуется включить в поиск только латинские буквы, надо использовать класс символов: Более безопасный метод состоит в том, чтобы включить в шаблон мнимые символы границы слова: Привязка к началу строки

Началу строки соответствует метасимвол (мнимый символ) ^ . Чтобы шаблон к началу строки, надо задать этот символ в начале регулярного выражения. Например, вот так можно проверить, что текст не начинается с точки:

Чтобы точка, указанная в шаблоне, не интерпретировалась как метасимвол перед ней пришлось поставить обратную косую черту.

Привязка к концу строки


Чтобы привязать шаблон к концу строки, используется метасимвол (мнимый символ) $ . В нашем примере мы используем привязку шаблона к началу и к концу строки, чтобы убедиться, что пользователь ввел только слово "exit":

Для проверки того, действительно ли пользователь ввел число, можно использо-вать метасимволы \d и \D . Метасимвол \D соответствует любому символу, кроме цифр. Например, следующий код проверяет, действительно ли введенный текст представляет собой целое значение без знака и паразитных пробелов:

To же самое можно проделать, использовав метасимвол \d:

Вы можете потребовать, чтобы число соответствовало привычному формату. То есть число может содержать десятичную точку, перед которой стоит по краййей мере одна цифра и, возможно, какие-то цифры после нее:

Кроме того, при проверке можно учитывать тот факт, что перед числом может стоять как плюс, так и минус (или пустое место):

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

Альтернативные шаблоны, если они присутствуют, проверяются слева направо. Перебор вариантов обрывается, как только найдено соответствие между текстом и шаблоном. Поэтому, например, порядок альтернатив в шаблоне (\.\d*|) мог бы стать критичным, если бы не привязка к концу строки. Наконец, вот как можно произвести проверку того, что текст является шестна-дцатеричным числом без знака и остальных атрибутов:

С помощью метасимвола \w можно проверить, состоит ли текст только из букв, цифр и символов подчеркивания (это те символы, которые perl называет словесными (word characters)):

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

Наконец, для проверки, что текст является идентификатором, то есть начинаетcя с буквы и содержит буквы, цифры и символы подчеркивания, можно испольpовать команду:

Как найти множественные совпадения

Для поиска нескольких вхождений шаблона можно использовать модификатор g . Следующий пример, который мы уже видели ранее, использует команду m/. / с модификатором g для поиска всех входжений буквы x в тексте:

Модификатор g делает поиск глобальным. В данном (скалярном) контексте perl помнит, где он остановился в строке при предыдущем поиске. Следующий поиск продолжается с отложенной точки. Без модификатора g команда m/. / будет упорно находить первое вхождение буквы х , и цикл будет продолжаться бесконечно.

В отличие от команды m/. / команда s/. /. / с модификатором g выполняет глобальную замену за один раз, работая так, будто внутри нее уже имеется встроенный цикл поиска, подобный приведенному выше. Следующий пример за один раз заменяет все вхождения х на z :

Без модификатора g команда s/. /. / заменит только первую букву х . Команда s/. /. / возвращает в качестве значения число сделанных подстановок, что может оказаться полезным:

Поиск нечувствительных к регистру совпадений

Вы можете использовать модификатор i , чтобы сделать поиск нечувствительным к разнице между заглавными и строчными буквами. В следующем примере про-грамма повторяет на экране введенный пользователем текст до тех пор, пока не будет введено Q , или q (сокращение для QUIT или quit), после чего программа прекращает работу:

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

Вызов функций и вычисление выражений при подстановке текста

Используя для команды s/. /. / модификатор е , вы тем самым показываете, что правый операнд (то есть подставляемый текст) - это то выражение perl, которое надо вычислить. Например, с помощью встроенной функции perl uc (uppercase) можно заменить все строчные буквы слов строки на заглавные:

Вместо функции uc($l) можно поместить произвольный код, включая вызовы программ.

Поиск n-го совпадения

С помощью модификатора g перебираются все вхождения заданного шаблона. Но то делать, если нужна вполне определенная точка совпадения с шаблоном, например, вторая или третья? Оператор цикла while в сочетании с круглыми cкобками, выделяющими нужный образец, поможет вам:

Этот пример можно переписать, используя цикл for:

Если же вам требуется определить нужное совпадение не по номеру, а по содержанию (например, по первой букве имени пользователя), то вместо счетчика $match можно анализировать содержимое переменной $1 , обновляемой при каждом найденном совпадении. Когда требуется не найти, а заменить второе или третье вхождение текста, можно применить ту же схему, использовав в качестве тела цикла выражение perl, вызываемое для вычисления заменяющей строки:

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

Как ограничить "жадность" квантификаторов

По умолчанию квантификаторы ведут себя как "жадные" объекты. Начиная с текущей позиции поиска, они захватывают самую длинную строку, которой может соответствовать регулярное выражение, стоящее перед квантификатором. Алгоритм перебора с возвратами, используемый perl, способен ограничивать аппетит квантификаторов, возвращаясь назад и уменьшая длину захваченной строки, если не удалось найти соответствия между текстом и шаблоном. Однако этот механизм не всегда работает так, как хотелось бы. Рассмотрим следующий пример. Мы хотим заменить текст "That is" текстом "That's". Однако в силу "жадности" квантификатора регулярное выражение " .*is " сопоставляется фрагменту текста от начала строки и до последнего найденного "is":

Чтобы сделать квантификаторы не столь жадными, а именно заставить их захватывать минимальную строку, с которой сопоставимо регулярное выражение, после квантификатора нужно поставить вопросительный знак. Тем самым квантификаторы принимают следующий вид:

  • *? - ноль или несколько совпадений,
  • +? - одно или несколько совпадений,
  • ?? - ноль совпадений или одно совпадение,
  • ? - ровно n совпадений,
  • ? - по крайней мере n совпадений,
  • ? - совпадений по крайней мере n , но не более, чем m.

Оратите внимание, что смыслквантификатора от этого не меняется; меняется только поведение алгоритма поиска. Если в процессе сопоставления шаблона и текста прототип определяется однозначно, то алгоритм поиска с возвратами увеличит "жадность" такого квантификатора точно так же, как он ограничивает аппетит собрата. Однако если выбор неоднозначен, то результат поиска будет другим:

Как удалить ведущие и завершающие пробелы

Чтобы отсечь от строки начальные "пробельные символы", можно использовать, следующую команду:

Чтобы отсечь "хвостовые" пробелы, годится команда:

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

Например в тексте нужно найти текст, находящийся между открывающим и закрывающим тегом:

найдет все слова, стоящие между тегами и .

В регулярных выражениях пристутствует своя семантика: быстрота, торопливость и возврат. Если квантификатор * совпадает во многих случаях, то в результате быдет выведен наибольший по длинне результат. Это жадность. Быстрота: поиск старается найти как можно быстрее. "Text"=

/m*/ , по смыслу символов m нет, но в результате будет возвращено значение . Т.е. формально и более символов.

потому что 1 элемент сторки - и более символов.

Если добавить квантификатор g , то результат будет таким:

т.к строка содержит 13 мест, где может встречатся o , в том числе и пустых.

  • /i игнорировать регистр
  • /x игнорировать пропуски в шаблоне и разрешить комментарии.
  • /g модификатор разрешающий выполнение поиска/замены везде, где это возможно
  • /gc не сбрасывается позиция при неудачном поиске.
  • /s разрешается совпрадение . с \n , игнорируется $* .
  • /m разрешить совпадение ^ и $ для начала и конца строки во внутренних переводах строк
  • /o однократная компиляция
  • /e правая часть s/// представляет собой выполняемый код
  • /ee правая часть s/// выполняется, после чего возвращаемое значение интерпретируется снова.

при вызове use locаle учитываются локальные настройки. Модификатор /g может заполнить массив значений @nums = m/(\d+)/g; но это сработает для ненакладывающихся совпадений. Чтобы поймать совпадения нужно воспользоваться оператором ?=. Если ширина = 0 , то механизм поиска остался на прежнем месте. Найденые данные остаются внутри скобок. Если есть модификатор /g , то текущая позиция остается прежней, но происходит перемещение на один символ вперед. $numbers="123456789"; @one=$numbers=

/(?=(\d\d\d))/g; print "@one \n"; print "@two \n";

Модификаторы m и s нужны для поиска последовательностей символов, содержащих перевод строки. При s точка совпадает с \n и игнорируется $* . m делает совпадающими ^ и $ до и после \n . e правая часть выполняется как программный код: perl -i -n -p -e 's/(.)/lc($1)/g' *.html приводит все литеры во всех файлах *.html текущей директории к нижнему регистру.

Встроенные переменные в regex.

$1, $2, $3, $4, . $n . содержат ссылки на найденный текст, только в том случае если regex был в круглых скобках:

внутри regex можно использовать переменные типа \1, \2, \3, \4, . \n, . найдет все урл, заключенные в двойные, одинарные и вообще без кавычек, находящиеся в документе.

$& содержит полный текст совпадения при последнем поиске.

$' и $` содержатся строки до и после совпадения

Если нужно скопировать и сделать подстановку, то нужно действовать примерно так:

Если нужно выцепить только алфавитные символы, с учетом настроек locale, то регексп примерно такой: /^[^\W\d_]+$/ в нем учитываются все не алфавитные символы, не цифры и не подчеркивания(для случая "ванька-встанька"), симвлол отрицания в группе [] - ^ , т.е. найти все, что не [\W\d_] , можно было написать и скажем так !

Для упрощения понимания сложных регулярных выражений можно воспользоваться их комментированием. Иногда правда можно только по виду регулярного выражения определить зачем оно предназначено:

читаем регулярное выражение:

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

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

Рабочие программы, использующие регулярные выражения

Выделение чисел в математической записи

Пример использования логических условий для нахождения любых чисел в том числе и в общепринятой математической записи:

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

в переменной $1 содержится то, что регулярное выражение находит в результате, т.е. m%(. )%gmi. m%((что-то)|([+-]?e[+-]?\d*[,.]?\d+))%gmi нужно для того, чтобы находить числа вида e-20 или E21 (так в математике обозначают десятку в какой-то степени, например e-0,20 = 10 -0,20 или E20 = 10 21 ). Рассмотрим левое регулярное выражение "что-то" для чисел вида не e20 или E21 :

[+-]? - есть ли в перед числом знак + или - . ? - если вообще есть что-то, находящееся внутри впереди стоящего [. ] . Выкинем проверку знака, регексп сократится до

рассмотрим regex (?=\d|[\.,]\d)\d* логический оператор (?=B) требует, чтобы перед числов было B . В данном случае B представляет из себя regex \d|[\.,]\d Regex \d|[\.,]\d значит, что перед каждым числом должно быть что-то либо просто число, либо число, перед которым стоит либо запятая, либо точка, т.е. находим все числа вида ,2 .2 или просто числа 2 ( 2 выбрано для примера, может быть и 3). Далее скобка закрывается и идет \d* , т.е. число вида ,2 точно пройдет(например ,2 e-,23 где перед запятой забыли поставить нолики, но мало ли бывает, забыли, надо и это предусмотреть. Вообще когда пишешь программу, надо предполагать, что е использовать будет ленивый склеротический чайник, правда не всегда возможно предугадать что учудит юзер, но к этому надо стремится), а вот число вида ,223 не пройдет. Да и regex (?=\d|[\.,]\d) говорит о том, что нужно найти только одну цифру после запятой. Для остальных цифр и нужен квантификатор \d* , который значит любое количество цифр, в том числе и ноль, т.е. оно работает и для числе вида .2 или ,2 Далее идет регулярное выражение ([\.,]\d*)? которое говорит о том, есть ли вообще точка и запятая(здесь всю полную строчку в принципе можно усовершенствовать) и число \d* (в том числе и его отсутствие, ведь квантификатор * значит любой символ в том числе и ноль). Отбрасывая все что было выше от этого большого регулярного выражения остается строчка:

Эта строчка отвечает за поиск в строке $_ математических обозначений степеней типа e201 , E,20 (число в степени 0,20 например a -0,20 ) и т.д. но только для подстрок вида -,034 e201 . Заметьте, что в конце стоит знак вопроса, т.е. если степенное обозначение вообще существует. (\se|e|\s?\^) есть ли числа вида -,034 e201 или -,034e201 и числа в "компьютерной" записи вида 2 ^-,3 = 2 -0,3 , т.е. этим регекспом мы разрешили пользователю ставить или не ставить пробел при указании степени и разрешили писать значек ^ с пробелом перед ним(если есть). Далее идет выражение ([-+]?\d*[,\.]?) , которое говорит о том, что степень может быть с + или - (типа e,-23 где юзер забыл поставть нолик, а на самом деле хотел написать a -0,23 ). Дальше идет цифра \d* (а может и не идет, т.к. квантификатор то * ). Потом идет либо точка либо запятая(причем тут негласно введено ограничение на использование запятой/точки, после e , если степень дробная или вообще есть, точка или запятая должна быть, иными словами не имеет смысла написать -2,34e-,23 , хотя юзер на самом деле хотел написать число -2,34 -0,23 ). Наконец мы добрались до конца: идет \d+ , но тут уж, пользователь, будь добр напиши хотя бы одно число, т.к. квантификатор + , а не * после \d . Т.е. наложили своего рода ограничения здравого смысла, можно просто написать 2 , а можно написать и 2e,- что суть бессмыленно. И еще, m%(что-то)%igm стоит квантификатор i , который разрешает e быть и заглавным и квантификатор x , который разрешает разносить регулярное выражение на несколько строк.

Прошу прошения что не ставил иногда знаки препинания, которые есть точка и запятая, тогда Вы бы подумали, что что-то лишнее написно и не подсечено как спецсимвол при помощи бэкслэша \ .

Итак, регулярным выражением

были предусмотрены числа степенного порядка, просто числа, числа со знаком, нецелые числа вида ,3(которое есть 0,3 или 0.3), ошибки пользователя при вводе чисел( типа -.034 e2,01 хотя надо бы писать либо -,034 e2,01 либо -.034 e2.01 хотя по смыслу перед точками и запятыми нужно ставить нули, но мы предусмотрели и это) и числа в "компьютерном" представлении.

Конечно, данное регулярное выражение не претендует на абсолютную работу, т.к. оно успешно не работает на подстроках вида -,045 e -,23 e-0.88 считая -,045 отдельным числом, а -,23 возводит в степень e-0.88 , хотя по идее должно было бы быть два числа -,045 e -,23 и e-0.88 , в таком случае еще одно ограничение пользователю: если хочется, чтобы степенные числа понимались корректно(для этой программы), то нельзя ставить пробел перед степенью e .

Облегчение поиска работы

Что делает эта программа, она составляет GET запрос из параметров, которые скрыты в h >Simple.pm отправляет запрос на сервер и как бы листает странички с поиском. Критерий ваших профессиональных навыков составлен в GET-запросе и осталось только разослать почту(для этого можно написать список рассылки) по адресам, которые выдала программа. Разберем регулярное выражение для вытаскивания почтового адреса из текущей странички s/(.*) ([\w+\-\.]+\@[\w\-\.]+\.\w<2,3>)(.*)/$2/ig .

[\w+\-\.]\@ - найти все что содержит буквы, тире и точки до символа @ , ведь почтовый адрес по спецификации может быть вида a Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript . Тоже самое после символа @ - [\w\-\.]+ далее может быть точка \. и любая буква от 2 до 3 символов \w , т.е. окончание, самый верхний домен .com , .ru , .cz и т.д. Далее регулярное выражение состоит из трех классов скобок (.*) - переменная $1 , ([\w+\-\.]+\@[\w\-\.]+\.\w<2,3>) переменная $2 и все остальное в (.*) - $3 . Пробел перед $2 стоит потому, что так устроен html, отдаваемый пользователю поиском по базе предложений о работе www.job.ru. Нам нужно содержимое $2 , в котором находится e-mail работодателя. Пишем его во вторую часть s/наш regex/$2/ig . Квантификатор i нужен для того, чтобы не различать регисты Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript и Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript , квантиикатор g задействова на тот случай, если работодатель указывает 2 адреса, по которым нужно высылать резюме. На 23 августа 2001 года на 20 часов 10 минут прогамма выдала 410 e-mail адресов(пролистав за 3-4 минуты 57 страниц), где вас ждут, как потенциального сотрудника.

Остается написать скрипт почтовой рассылки по e-mails, выданным данным скриптом. Но это в другой главе.

Примером выше был получен спсиок email адресов. Теперь необходимо проверить, действительно ли существуют домены, на которых заведены такие пользщователи(примитивная - но проверка).

Переписываем исходную программу с учетом вышеприведенного кода Между строчками можно комментировать целые куски кода.

Эта программа успешно удалила некторые из адресов, которые Socket.pm показались подозрительными. Все-таки какую-никакую, а проверку существования e-mail адресс окольными путями при помощи perl провести можно. Автору сего текста все-таки больше нравится вариант, заключенный в комментарии =pod(.*?)=cut. Он просто короче. Да и если научится читать сложные регулярные выражения, то можно написать полный регексп е-mail адресов, который занимается тем, что выделяет адреса в точности с соответствующим RFC(занимает это регулярное выражение несколько страгниц). Но впрочем ниже будет подглава, посвященная чтению монстрообразных, на первый взгляд, регекспов налету, со множеством примеров, выше же мы уже попытались угадать предназначение регулярного выражения только по его виду.

Ключи, которые использовались в вышеприведенном регулярном выражении

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

Разберем один интересный момент в данном регекспе:

Тут проявляется пожалуй одна из действительно сильнейших особенностей regex , возможность в одном регулярном выражении избежать многострочных условий с циклом. В приведенном примере работает все примерно так: Если $addr=gethostbyname($1) - да, то ставить ip-адрес( inet_ntoa($addr) ), если нет(не откликнулся сервер, сбой на линии и пр) то метить этот урл как подозрительный [. ] . В принципе в программе ничего человеку делать не нужно, т.к. подозрительные отметаются условием print $file,"\n" if($file !

/\?\?\?/); Общее время работы программы 10-15 минут.

Очень простое решение для зеркала новостной ленты

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

Вывод результатов поиска

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

Исходная задача состоит в следующем: вывести по 4 слова спереди и сзади результата поиска, причем так, чтобы если слово находится первым, то будет видно 4 слова позади него. В точности такое-же условие и для последнего слова.

Соответственно из вида регекспа понятно, что разделителями слов могут быть символы [\s,\.\n^]* , в том числе и символ перевода каретки ^ . Комбинация (\d\d\d) значит что нужно найти 3 цифры три раза.

Perl Template Toolkit - Шаблоны предварительной обработки обратно в скрипт Perl

Простите меня, если этот вопрос уже задан и/или ответил в другом месте.

Прежде чем начать, я должен указать, что характер этого запроса может не требовать добавления кода в этот поток, скорее ответ может быть просто ссылкой на документацию модуля Template Toolkit с комментарием "ПРОЧИТАЙТЕ ЭТО СНОВА" :). Чтобы быть более ясным, я бы согласился на краткий ответ "ДА" или "НЕТ".

Скажем, у меня есть рабочий скрипт perl, который обрабатывает шаблоны Template :: Toolkit без проблем.

Но один из моих шаблонов содержит "имена" (имена людей, имена серверов, в конце концов это действительно не имеет значения: просто "имена"). Эти имена используются для создания FILENAMES, содержащих обработанные данные позже.

Сегодня у меня это работает через следующий псевдокод:

Затем я беру сгенерированный список "имен" в "output.txt", и я вставляю их в массив внутри одного исполняемого скрипта Perl. Этот список затем используется итеративным способом для вывода данных, указанных в другом шаблоне, и назовите каждый результирующий файл на основе оригинального "имени":

Как я уже сказал, все это прекрасно работает (на самом деле, отлично). Моя проблема в том, что он раздувает мой код без необходимости (нужно управлять открытыми FH и т.д.). Там есть ГОТ, чтобы быть лучшим способом, учитывая ТТ чрезвычайных полномочий.

Поэтому я начал читать о включенных модулях Template :: Toolkit (например: STASH, PROVIDER и т.д.). Я понимаю, что STASH, например, позволяет вам вводить данные в существующий объект модуля шаблона дополнительным образом, однако это полярная противоположность тому, что я хочу делать.

Мой фактический вопрос (опять же, ДА или НЕТ было бы просто отлично, если бы ответы на вопрос о том, возможно ли это или нет):

Возможно ли, чтобы скрипт Perl считывал шаблон, например тот, который содержит объект HASH с шаблоном-Toolkit, и создает новый HASH, который можно использовать с помощью реального скрипта Perl (например, вне шаблона)?

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

Спасибо, пожалуйста, поймите, что я сделал все возможное, чтобы создать полезную псевдомодуль, поскольку реальный код включает конфиденциальные элементы и, к сожалению, исключает раскрытие. Надеюсь, ты поймешь. Я могу предоставить другие "очищенные абстракции/примеры" по мере необходимости.

ОБНОВИТЬ

В ответ на пользователя икегами:

Во-первых, спасибо за ответ.

Хорошо, давайте начнем с одного из ваших комментариев: ". что не имеет смысла, поскольку TT не хранит хэши". Хм. Если мы не говорим о двух разных вещах, это неправильно, поскольку я делаю это сегодня.. например, вот объект, размещенный в Шаблоне, содержащий элементы начального хэша, о котором я говорил:

Еще раз, выше работающий, и он существует в TT. и, если я не ошибаюсь, выше, конечно, выглядит, чувствует и на вкус, как хэш. Я даю вам, однако, что он заключен в массив. так что, возможно, это не 100% Grade-A "Pure HASH object", но я, конечно, использую его как хэш (и довольно хорошо тоже).

Прежде чем вы что-нибудь скажете, я уже признаю, что мне, скорее всего, нужно будет обновить имена ключей, чтобы быть UNIQUE для простоты разбора (хеш-ключи сами по себе должны быть уникальными), но это отдельная работа.

Вы были правы, когда сказали: "Это явно не то, что вы хотели спросить". Позвольте мне уточнить окончательный вопрос, как вы просили:

Может ли Template Toolkit из исполняемого скрипта Perl читать "Шаблон 1", который содержит один объект HASH (как описано выше), и читать указанную структуру HASH в новый хеш-объект, который существует только внутри указанного исполняемого скрипта (в отличие от сам шаблон)? Этот "новый хеш" в конечном итоге будет использоваться для обозначения файлов, созданных "Шаблон 2".

Наконец, чтобы удовлетворить ваш последний запрос:

Вышеприведенная выдержка содержит запрошенный "вход". Результат, который я хочу получить, будет истинным хэшем Perl, полученным из данных внутри вызываемого шаблона.

Так как эквивалент Perl (желаемый OUTPUT):

. будет использоваться для "подачи" определенных значений, например, значений "NAME", в другие обработанные шаблоны "позже".

Надеюсь, это прояснит путаницу. еще раз спасибо ikegami.

Шаблоны документов и perl

Всегда, когда нам необходимо написать CGI скрипт на Perl мы сталкиваемся с тем, что скрипт должен возвращать пользователю некоторый HTML код. Как правило, этот код вставляется непосредственно в код самого скрипта. Данный подход не совсем удобен в том плане, что при изменении дизайна сайта, как правило, приходится изменять текст скрипта. Вы наверно замечали, что очень часто "скриптовая" часть сервера несколько отличается от остальной части сайта. Происходит это именно по той причине, что в самом коде скрипта довольно сложно изменять HTML фрагменты. Где-то да просчитаетесь.

Второй, наиболее популярный, вариант - это вынесение переменных с HTML в отдельный файл. Это конечно облегчает жизнь, но не дает полной свободы. Предложенный ниже скрипт состоит всего лишь из 30 строк, но зато он решает все описанные выше проблемы.

Итак, для начала решим, что все наши HTML данные будут храниться в файле - шаблоне. Назовем его html.dot Формат файла будет следующий:

Кроме того, в тексте можно использовать такие конструкции:

@Имя@ - подставить значение переменной "Имя"

@#Имя@ - подставить фрагмент с названием "Имя". Заметьте, что подстановка идет рекурсивно и в подставляемых блоках, так же можно использовать подстановки.

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

2 - Открываем файл. Имя файла должно быть передано как аргумент функции.
3 - Пробегаем по всем строчкам файла.
4 - Избавляемся от символа конца строки.
5 - Если строка начинается с "#" (причем после нее стоит не "!"), то работаем с ней. Иначе - теряем. Поскольку это комментарий.
6 - Если строка начинается на "#!", значит это название очередного фрагмента.
7 - Запомним имя текущего фрагмента.
9-10 - Если это просто строка, добавляем ее в элемент хеша с именем равным имени текущего фрагмента.
14 - Закрываем файл.

Процедура рекурсивной подстановки

16 - Пробегаем по всем элементам хеша %DOT.
17 - Заменяем все конструкции вида @#NAME@ на текст фрагмента с именем "NAME".
Вот и все. У нас готов глобальный хеш %DOT, в котором содержатся все наши шаблоны.

Возьмем для примера такой файл-шаблон: После обработки получим хеш из трех элементов MAIN, STYLE, TITLE.

Ну и наконец напишем функцию, которая будет подставлять значения переменных. Что бы переменные не пересекались с переменными, используемыми в скрипте, будем хранить их в хеше %DOT_VAL.

1 - Если функция вызывается с аргументом, то замена переменных происходит в этом аргументе. Иначе замена переменных происходит во всем хеше $DOT.
2 - Подстановка переменных.
5 - Бежим по всем элементам хеша %DOT
6 - Подставляем значения переменных.

Илон Маск рекомендует:  Внешняя рамка элемента. Свойство outline
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL