The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"Раздел полезных советов: Обработка иерархически связанной ст..."
Вариант для распечатки Архивированная нить - только для чтения! 
Пред. тема | След. тема 
Форумы Разговоры, обсуждение новостей (Public)
Изначальное сообщение [Проследить за развитием треда]

"Раздел полезных советов: Обработка иерархически связанной ст..."
Сообщение от auto_tips on 29-Дек-05, 15:28 
Как-то пришлось столкнуться с обработкой иерархически связанной структуры на perl.
В инете есть куча разрозненной информации по этому поводу.
Можно, например, воспользоваться пакетами с сайта CPAN. Но с одной
стороны
стрелять из пушки по воробьям ... не дело.. а с другой надо чтобы и в мозгах что-то осталось.
Вообщем, задачка решилась и заодно родился вот такой скриптик, не претендующий
на уникальность, тем более, что на perl (как и на других мощных языках) одну и ту же задачу
можно решить многими способами. Хотя, эффективность этих способов - это уже другой вопрос.

Итак, скрипт.

#!/usr/bin/perl
# Рассмотрим принцип работы рекурсивных функций и построения
# связанных структур (в данном случае анонимных хэшей) на
# примере скрипта для иерархического (в виде дерева)
# отображения подкаталогов, содержашихся в заданном каталоге.
#
# Сначала необходимо провернуть некоторые подготовительные
# операции. Например, определиться какой каталог будем печатать.
print "Directory to print [.]: ";
# Считываем каталог и удаляем символ конца строки.
chop (my $d = <>);
# По умолчанию берем текущий каталог.
if (!$d) {$d="."};
# Проверяем, является ли $d каталогом...?
(-d $d) or die "Error: $d isn\'t directory.\n";

# Теперь создаем дерево вложенных хэшей с помощью
# функции MakeTree, которая возвращает указатель
# на корневой хэш.
my $root = MakeTree($d);
# И печатаем. Первый параметр - уровень вложенности
# текущего каталога - $d.
PrintTree(0,$root);

# Рассмотрим подробнее рекурсивные функции MakeTree и PrintTree
sub MakeTree {
# Берем первый параметр - каталог для обработки
my $path_to_dir = shift;
# Инициализируем хэш, в котором будем сохранять
# результат обработки каталога $path_to_dir.
my %branches;
# Читаем содержимое каталога в массив @content.
# Причем выбрасываем из рассмотрения каталоги
# "." (текущий), ".." (уровнем выше) и файлы.
opendir DIR, $path_to_dir;
my @content = grep { !/^\.{1,2}$/
&& !(-f $path_to_dir."/".$_) } readdir DIR;
closedir DIR;
# В итоге в @content содержится список каталогов,
# находящихся в $path_to_dir. Теперь для каждого
foreach my $dir (@content) {
# каталога из этого списка рекурсивно запускаем
# эту же функцию - MakeTree, в аргументе которой
# уже новый путь - путь к каталогу $dir.
$branches{$dir} = MakeTree($path_to_dir."/".$dir);
# В результате в хэш %branches по ключу $dir заносится
# значение, возвращаемое функцией MakeTree. А это значение
}
# ничто иное, как указатель на хэш, поскольку функция
# MakeTree возврашает указатель на хэш %branches, как мы
# видим ниже. Ключи этого хэша - каталоги, содержащиеся
# в $dir, а значения по этим ключам - опять же указатели на
#хэши...и т.д.
return \%branches;
# Но ведь %branches обьявлен с ключевым словом my и ограничен
# областью видимости функции (в данном случае)?!..Это означает,
# что сборщик мусора perl должен уничтожить %branches при
# выходе из функции. Оказывается, нет. Дело в том, что пока для
# переменной (в данном случае - хэш), объявленной с оператором
# my внутри блока { } существует указатель вне этого блока, то
# perl не уничтожает переменную, и мы приходим к понятию
# анонимная переменная (хэш). Т.е. мы обращаемся к переменной
# не $имя_переменной, а через указатель.
}
# Таким образом, в результате создаются ссылающиеся друг
# на друга анонимные хэши, которые существуют до тех пор,
# пока существует указатель $root.

# Печатаем результат.
sub PrintTree {
# Первый параметр - уровень вложенности каталога.
my $level = shift;
# Второй - хэш, содержащий имена каталогов, через указатель.
my %top = %{(shift)};
# Далее для каждого ключа из хэша %top
foreach $key (keys %top) {
# печатаем сам ключ (на самом деле ключ - имя каталога),
# причем с отступом 4*$level.
printf ("%${\(4*$level)}s$key\n","|");
# Необходимо заметить, что в %top по ключу $key содержится
# хэш с именами каталогов, которые тоже было бы неплохо
# распечатать. Поэтому увеличиваем уровень вложенности
$level++;
# и опять вызываем PrintTree.
PrintTree($level,$top{$key});
# После чего надо вернуть уровень вложенности на место.
$level--;
}
}


URL:
Обсуждается: http://www.opennet.me/tips/info/947.shtml

Cообщить модератору | Наверх | ^

 Оглавление

Сообщения по теме [Сортировка по времени, UBB]


1. "Обработка иерархически связанной структуры на Perlна perl."
Сообщение от Критик on 29-Дек-05, 15:28 
По поводу "эффективность".

Есть более красивое решение без рекурсии.

Подсказка: берем массив, загоняем первый элемент и поехали. В цикле while(shift <наш массив>). Новые каталоги загоняем (push unshift) в массив. И никакой рекурсии.

Cообщить модератору | Наверх | ^

2. "Обработка иерархически связанной структуры на Perlна perl."
Сообщение от Andrey Karavaev email on 30-Дек-05, 21:56 
Более того - есть и более эффективные.
И без всяких подсказок ;).
Моя первоначальная задача была совсем не про
директории и не про вывод на консоль :).
Пришлось сильно упростить не теряя сути полезного
алгоритма.
Cообщить модератору | Наверх | ^

Удалить

Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру