Однострочник месяца на Perl: Пригоден к государственной службе
Автор: Ben Okopnik
Перевод: Павел Соколов


Когда Вумерт Фунли открыл дверь в ответ на настойчивый стук, он обнаружил перед собой двоих типов, размерами (и формой) напоминающих холодильник, в тёмных плащах и с хмурыми минами на лицах. Он заметил, что руки обоих субъектов были в карманах, годы занятий единоборствами и внимание к деталям привели его к незамедлительным действиям.

-- Здравствуйте. Вы определённо работаете на правительство, и вы здесь чтобы помочь мне, даже если я и не звал вас. Могу я видеть ваши удостоверения? А, Та Самая служба. Входите, джентльмены. Можете снять ваши профессиональные мины, а также плащи -- они вам не понадобятся. Прошу меня извинить, мне придётся прервать разговор и позвонить вашему начальству, чтобы убедиться, что всё в порядке. Мне надо быть уверенным в ваших полномочиях. Присаживайтесь.

Несколько минут спустя он положил телефонную трубку.

-- Ну что ж, кажется всё правильно. Как я могу помочь вам? Или, что ближе к истине, вашим сотрудникам, которые столкнулись с проблемами в программировании? Я понимаю, что меры безопасности очень жестки в последнее время и ваша организация предпочитает встречи с глазу на глаз в безопасной обстановке, так что я озадачен вашим появлением здесь. Обычно я не сужу о людях по их внешности, но вы определённо не программисты.

Агенты посмотрели друг на друга, не говоря ни слова поднялись и начали экспресс-осмотр квартиры Вумерта (и самого Вумерта). Исследование безопасности велось набором дорого выглядящих инструментов. Когда несколько минут спустя они закончили, они снова посмотрели друг на друга и синхронно кивнули. Затем каждый из них извлёк из недр своих плащей программистов слегка помятого вида, которых аккуратно поместили перед Вумертом. Ритуал со взглядом и кивками повторился, после чего агенты отошли в противоположные углы комнаты, чтобы затаиться, притворившись большими тенями.

Вумерт моргнул.

-- Хорошо. Требования безопасности должны быть выполнены... любой ценой. Присаживайтесь, джентльмены, я приготовлю чай.

Ещё несколько минут спустя, после представлений и горячего чая (оказалось, что живой груз зовут Цеде Тильда и Арти Эффэм) они перешли к делу. Арти оказался спикером этой парочки.

-- Мистер Фунли, на сегодня основной нашей задачей является обработка изображений. Как вы можете себе представить, мы получаем множество данных от наблюдений...они поступают к нам в стандартизированном формате, который содержит множество информации помимо самого изображения: IP адрес исходного сайта, комментарий, информация о положении и т.п. Проблема же в том, что мы оба знакомы с обработкой текста в Perl, но не имеем представления, как подойти к извлечению набора нетекстовых записей или, в данном случае, как избежать чтения 200 Мб файла с изображением, когда то, что нам нужно -- всего лишь информация из заголовка. Признаюсь, мы застряли. Наш местный гуру C++ продолжает попытки убедить нас, что это может быть проделано на его любимом языке не более, чем за неделю, но мы уже слышали такую песню и ранее.

После энергичного кивка Сиди, он продолжил.

-- В любом случае, мы подумали, что нам стоит проконсультироваться с вами -- должно же быть что-то, что вы сможете сделать!

Вумерт кивнул.

-- Да, конечно. Только один момент: так как мы не рассматриваем конкретные засекреченные данные или что-либо, что требует допуска, я полагаю, что вы принесли мне тщательно проверенный лист со спецификацией, не так ли? Так вот, я бы хотел, чтобы мой помощник Фринк Ублик, присутствовал на обсуждении. Этот вопрос, в действительности, похож на работу, которую он недавно пытался проделать, так что ему это скорее всего тоже будет полезным.

Пара агентов, которых Вумерт окрестил Сильным и Молчаливым, привели и обезжучили Фринка, хотя никаких следов дебаггера "perl -d" [1] не было заметно. Представившись всем присутствующим, он сел на свой любимый плетёный стул, откуда он мог видеть экран Вумерта.

-- Хорошо, посмотрим на спецификацию. Хммм... заголовок состоит из 1024 байтов; четыре байта на IP адрес; 40 на комментарий; широта и долгота верхнего левого и нижнего правого углов, причём перед каждой из четырёх координат стоит символ, определяющий длину. Так, этого хватит для начала. Дальше вы сможете экстраполировать это решение и на оставшиеся поля.

-- Что ты думаешь, Фринк? Есть идеи, как подступиться к этой проблеме?

Фринк уже откинулся на спинку стула и размышлял.

-- Да, идеи есть, по крайней мере по первой части. Так как они читают бинарный файл, "read" кажется наиболее подходящим ответом. Что до второго... ну, может быть "substr"...

-- Близко, но не совсем. Инструкция "read" правильно подобрана: мы хотим получить кусок файла фиксированной длины. Однако, "substr" не очень подходит для использования с нетекстовыми строками -- и совсем бесполезна, когда мы не знаем заранее длины полей, как в случае четырёх координат широты/долготы. Однако у нас есть пушка помощнее... эээ, парни, успокойтесь! -- добавил он, когда Сильный и Молчаливый выдвинулись из углов. -- это всего лишь образное выражение!

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


# Только фрагмент кода, обработка полученных данных оставлена как домашнее задание
...
$A="file.img";open A or die "$A: $!";read A,$b,1024;@c=unpack "C4A40(A/A)4", $b
...

Молчание длилось, пока Цеде не прочистил горло.

-- А... Мистер Фунли...что, чёрт возьми, это такое? Я могу понять функцию "open", даже если она выглядит немного странно... "read" также выглядит разумно... но что за синтаксис у "unpack". Выглядит так же странно, как подтяжки-змеи.

Вумерт взглянул вокруг. Арти согласно кивал, и даже Фринк казался озадаченным. Он улыбнулся и глотнул чая.

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


$A = "file.img";                # Присвоить $A название файла
open A or die "$A: $!";         # Открыть, используя "новый" синтаксис
read A, $b, 1024;               # Прочитать 1кб из "A" в $b
@c = unpack "C4A40(A/A)4", $b;  # Распаковать $b в @c по шаблону

Новый синтаксис "open" (начиная с Perl 5.6.0) позволяет "объединить" имя переменной-указателя на файл и собственно имя файла, что я проделал в первых двух строчках. Имя переменной(без знака " $") используется, как указатель на файл. Если вы взглянете в "perldoc -f pack", там содержится список модификаторов для шаблона, практически всё, что вы можете захотеть от преобразований: вы можете преобразовывать различные типы данных, двигаться вперёд, отступать и практически танцевать джигу. Использованный мной шаблон был на самом деле довольно простым:


C4      Значение 1-байтового типа "char", повторённое 4 раза
A40     Строка из 40 символов ASCII
(A/A)4  Строка символов ASCII, перед которым стоит поле "длины", которое само по себе -- один символ; повторяется 4 раза

Результат этой операции был присвоен @c, которая теперь содержит примерно следующее:


$a[0]   Первый октет IP адреса
$a[1]    "  второй     "    "    "    "
$a[2]    "  третий     "    "    "    "
$a[3]    "  четвёртый  "    "    "    "
$a[4]   Поле комментария
$a[5]   Широта левого верхнего угла
$a[6]    "  долгота    "    "    "    "    "
$a[7]   Широта нижнего правого угла
$a[8]    "  долгота    "    "    "    "    "

-- Очевидно, что вы сможете продолжить этот процесс для оставшихся данных. Как вы думаете, джентльмены, это удовлетворяет вашим требованиям?

После того, как теперь полные энтузиазма Арти и Цеде были упакованы своими громадными хранителями и в квартире снова стало так же просторно, как и до их прибытия, Вумерт открыл бутылку коньяка Hennessy "Paradise" и принёс пару маленьких, но ароматных сигар, которые оказались Cohibas высшего класса.

-- Ну что, Фринк, это ещё решённое нами дело; это всегда заставляет меня чувствовать себя великолепно. Что до тебя -- читайте книги, молодой человек! По крайней мере, когда мы разберёмся с этой небольшой наградой. "perldoc perlopentut" может стать хорошим введением в разные способы открытия фала, дуплицирования указателя на файл и т.п.; "perldoc -f pack" и "perldoc -f unpack" объяснят эти функции в деталях. Когда ты решишь, что разобрался, найди бинарный файл с документированным форматом и напиши парсер, который будет доставать данные для изучения. Завтра к этому времени ты должен быть уже экспертом в использовании этих инструментов...



[1] Perl поставляется с очень мощным встроенным дебаггером; детали см. в "perldoc perldebtut" и "perldoc perldebug". Однако отметьте, что он не очень подходит для поиска скрытых передатчиков или подслушивающих устройств.

Бен -- сотрудничающий редактор Linux Gazette и член Банды ответчиков (в смысле, они отвечают на возникающие вопросы читателей. Прим. перев.)

Бен родился в Москве в 1962 г. В шесть лет заинтересовался электричеством -- продемонстрировав это, воткнув вилку в розетку и вызвав пожар. С тех пор неоднократно проваливался в технологические люки. Он начал работать с компьютерами ещё в старые, добрые времена, когда их приходилось собирать из деталей и припаивать на печатные платы, а программы должны были умещаться в 4k памяти. Он с радостью заплатил бы внушительную сумму любому психологу, способному излечить его от вызванных этим кошмаров.

Последующий опыт Бена включает создание программ практически на дюжине языков, поддержку сетей и баз данных во время приближающегося урагана, а также написание статей для публикаций в разных местах: от журналов по парусному спорту до техножурналов. Завершив недавно семилетний круиз по Атлантике/Карибскому морю под парусом, он на данный момент пришвартовался в Балтиморе, где работает техническим инструктором в Sun Microsystems.

Бен работает с Linux с 1997, и считает, что именно из-за него у Бена полностью пропал интерес к развязыванию атомной войны в разных частях северо-запада Тихого океана.


Copyright © 2003, Ben Okopnik. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 88 of Linux Gazette, March 2003


Вернуться на главную страницу