Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
rubin
Зарегистрирован: 15.06.2006 Сообщения: 5 Откуда: Санкт-Петербург
|
Добавлено: Чт Июн 15 2006 16:25 Заголовок сообщения: (Perl) Как выгрузить в файл текст который лежит в хеше? |
|
|
Добрый День.
Есть у меня одна проблема, я написал парсер на Perl (беру файл, запихиваю его в массив, далее построчно регулярными выражениями распихиваю строки по хешам как мне надо, соблюдая структуру начального файла). Теперь когда у меня файл разложен в хеше его надо выгрузить в другой файл в том же виде и порядке как и в исходном файле, а вот как это сделать - понять не могу. Может кто подскажет?
Код:
#!/usr/bin/perl -wopen
(FILEHANDLE, "<services3.cfg"); # открываем файл для чтения
@text = <FILEHANDLE>; # передаем в массив содержимое
FILEHANDLEclose (FILEHANDLE);
%hash = (); # создаю пустой хеш
$var = 0;
$temp = 0;
$val = "val";
$rem = "rem";
$keystone = '';
$open = 0;
for ($loop_ind=0; $loop_ind<=$#text; $loop_ind++) # открываю цикл по строкам FILEHANDLE
{ #проверка пустой стоки текста
if ($text[$loop_ind] =~ m/(^$)|(\x09)|([\ ]+\n)/)
{ if ($open == 0)
{$var++;
$hash{$var} = $text[$loop_ind];
}
else
{ if ($num == 0)
{$keystone = "Clear";
if ((ref $hash{$var}{$temp}{$num}) eq 'HASH')
{$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $text[$loop_ind];}
else
{$hash{$var}{$temp}{$num} = {$keystone => {$rem => $text[$loop_ind]}};}
}
else
{$keystone = "Clear";
$num++;
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $text[$loop_ind]; }
}
}
else
{# проверка строки на наличие символов "закрытия секции"
if ($text[$loop_ind] =~ m/([\ ]+)*(\})/)
{if ($text[$loop_ind] =~ m/(\#)/)
{}
else
{ if ($text[$loop_ind] =~ m/(\;)/)
{# проверка строки на наличие символов "закрытия секции" с коментариями
if ($text[$loop_ind] =~ m/([\ ]+)*(\})*([\ \x09]+)*(\;)*([\ \x09]+)*([\W\w\d\'\"\S\s\n]+)/)
{$keystone = "Clear";
$num++;
$hash{$var}{$temp}{$num}{$keystone} -> {$val} = $1.$2.$3.$4.$5.$6;
$open = 0;
}
}
else
{$keystone = "Clear";
$num++;
$hash{$var}{$temp}{$num}{$keystone} -> {$val} = $text[$loop_ind];
$open = 0;
}
}
}
else
{# проверка строки на наличие "шарпа" - вся строка записывается как ремарка
if ($text[$loop_ind] =~ m/(\#)/)
{if ($open == 0)
{$var++;
$hash{$var} = $text[$loop_ind];
}
else
{if ($num == 0)
{$keystone = "Sharp";
if ((ref $hash{$var}{$temp}{$num}) eq 'HASH')
{$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $text[$loop_ind];}
else
{$hash{$var}{$temp}{$num} = {$keystone => {$rem => $text[$loop_ind]}};}
}
else
{$keystone = "Sharp";
$num++;
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $text[$loop_ind];
}
}
}
else
{# проверка строки на предмет начала секции
if ($text[$loop_ind] =~ m/(define)*(\ )*([A-Za-z]+) *(\{)/)
{if ($text[$loop_ind] =~ m/(\;)/)
{# проверка строки на предмет начала секции с коментариями
if ($text[$loop_ind] =~ m/(define)*(\ )*([A-Za-z]+) *(\{)*([\ \x09]+)*(\;)*([\ \x09]+)*([\W\w\d\'\"\S\s\n]+)/)
{$var++;
$num = 0;
$open = 1;
$temp = $1.$2.$3.$4.$5.$6.$7.$8;
$hash{$var}{$temp} = {$num =>''};
}
}
else
{$var++;
$num = 0;
$open = 1;
$temp = $1.$2.$3.$4;
$hash{$var}{$temp} = {$num =>''};
}
}
else
{# проверка строки пренадлежащей к секции на наличие коментариев
if ($text[$loop_ind] =~ m/(\;)/)
{# парсинг строки с коментариями
if ($text[$loop_ind] =~ m/([\ \x09]+)*([A-Za-z\_\-]+)*([\ \x09]+)*([A-Za-z\d\_\-\!\%\:\"\,\.\n]+)*([\ \x09]+)*(\;)*([\ \x09]+)*([\W\w\d\'\"\S\s\n]+)/)
{if ((ref $hash{$var}{$temp}{$num}) eq 'HASH')
{$keystone = $2;
$num++;
$hash{$var}{$temp}{$num}{$keystone} -> {$val} = $4;
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $8;
}
else
{$keystone = $2;
if ($num == 0)
{$hash{$var}{$temp}{$num} = {$keystone => {$val => $4}};
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $8;
}
else
{$num++;
$hash{$var}{$temp}{$num} = {$keystone => {$val => $4}};
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = $8;
}
}
}
}
else
{# парсинг строки без коментариев
if ($text[$loop_ind] =~ m/([\ \x09]+)*([A-Za-z\_\-]+)*([\ \x09]+)*([A-Za-z\d\_\-\!\%\:\"\,\.\n]+)/)
{if ((ref $hash{$var}{$temp}{$num}) eq 'HASH')
{$keystone = $2;
$num ++;
$hash{$var}{$temp}{$num}{$keystone} -> {$val} = $4;
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = "\n";
}
else
{$keystone = $2;
if ($num == 0)
{$hash{$var}{$temp}{$num} = {$keystone => {$val => $4}};
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = "\n";
}
else
{$num ++;
$hash{$var}{$temp}{$num} = {$keystone => {$val => $4}};
$hash{$var}{$temp}{$num}{$keystone} -> {$rem} = "\n";
}
}
}
}
}
}
}
}
}
При этом содержимое исходного файла services3.cfg такое:
Код:
# test message
define service{ ; sdfsadf
name generic-service ; The 'name' of this service template, referenced in other service de
active_checks_enabled 1 ; Active service checks are enable
register 0 ; DONT REGISTER THIS DEFINITION - ITS NOT A REAL SERVICE, JUST A TEMPLATE!
} ; temp message
# test message
define service{ use generic-service
host_name router-fcu
}
# Service definition
#define service{
# use generic-service ; Name of service template to use
#
# notification_period 24x7
# }
Секция начинается с "define service{", а заканчивается " }".
Собственно как мне записать распарсенный текст в таком же виде построчно выкинув его в новый файл format.cfg???
Все сто стоит после шарпа "#" - это ремарка или просто коментарий. |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Чт Июн 15 2006 20:37 Заголовок сообщения: |
|
|
Рекурсивно....
Обход сколь угодно страшной структуры делается примерно так:
Код: | sub Unparse {
$_ = shift;
$prefix = shift;
if (ref eq "SCALAR") {
Unparse($$_, $prefix)
} elsif (ref eq "ARRAY") {
my @a = @$_;
Unparse($a[$_], "$prefix["."$_]") for 0..$#a
} elsif (ref eq "HASH") {
my %a = %$_;
Unparse($a{$_}, "$prefix{"."$_}") for keys %a
} else { # Кажется наткнулись на не-ссылку (или что-то blessнутое)
Сделать что-то интересное. Например так:
print "$prefix = $_";
}
} |
_________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
rubin
Зарегистрирован: 15.06.2006 Сообщения: 5 Откуда: Санкт-Петербург
|
Добавлено: Пт Июн 16 2006 08:51 Заголовок сообщения: |
|
|
Большое спасибо.
Про рекурсивный метод я подумывал уже (прочитав о нем в книге).
Но так как я язык этот изучаю всего 1,5 недели, то мне трудно еще во все въехать!
В частности не могли бы Вы Aragaer, слегка разжевать написанный код, просто не совсем понимаю что, от куда и куда. Дальше буду переделывать под себя.
Спасибо. |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Пт Июн 16 2006 08:58 Заголовок сообщения: |
|
|
На вход мы получаем некий скаляр, который может быть ссылкой на что-либо, а может быть собственно литерадом (значение, которое надо вывести). Если это ссылка - разыменовываем ее и продолжаем мучаться. Ссылка на массив - разбираем каждый элемент массива. На хеш - каждый элемент хеша. Переменная $prefix в моем примере отслеживает глубину вложения.
В том виде, как я написал, скрипт не будет работать с объектами - они попадут на else, а должны попасть куда-то еще. Имеет смысл сделать так: Код: | } elsif (!ref) {
работаем с литералом
} else {
а вот теперь уже точно какой-то левый объект
} |
Хотя да, код у меня получился немного навороченным (в смысле использует прорву особенностей языка....) Попробую попозже написать его более внятно. _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
rubin
Зарегистрирован: 15.06.2006 Сообщения: 5 Откуда: Санкт-Петербург
|
Добавлено: Пт Июн 16 2006 09:10 Заголовок сообщения: |
|
|
Да уж, без пол литра не разберешься!
А можно мне в аську писать? |
|
Вернуться к началу |
|
|
rubin
Зарегистрирован: 15.06.2006 Сообщения: 5 Откуда: Санкт-Петербург
|
Добавлено: Пт Июн 16 2006 10:14 Заголовок сообщения: |
|
|
Если будет минутка, не напишите, как мне начать построчно, обязательно по порядку (с 0 до конца) выводить хеш в файл.
Вообще если в дебагере запустить мой код, то структура хеша такая:
Код: |
%hash = ...
1 = '\n'
2 = '#define service{\n'
3 = '# name generic-service ; The \\'name\\' of this service template, \n'
4 = '# active_checks_enabled 1 ; Active service checks are enabled\n'
5 = '# жЕДЕТБМШОЩК гЕОФТ хРТБЧМЕОЙС\n'
6 = ' \n'
7 = '\n'
8 = HASH(0x1d2ae98)...
'define service{' = HASH(0x1d2aee0)...
0 = HASH(0x1ae8020)...
'use' = HASH(0x1ae7e7c)...
'rem' = 'Test rem\n'
'val' = 'generic-service'
1 = HASH(0x1ae7bb8)...
'host_name' = HASH(0x1cd6298)...
'rem' = 'woeirjwerfwf\n'
'val' = 'router-fcu'
10 = HASH(0x1d2add8)...
'contact_groups' = HASH(0x1ae8200)...
'rem' = '\n'
'val' = 'admins\n'
11 = HASH(0x1ae7cd8)...
'notification_interval' = HASH(0x1ae7f3c)...
'rem' = '\n'
'val' = 120\n
12 = HASH(0x1d2ae08)...
'notification_period' = HASH(0x1ae8668)...
13 = HASH(0x1d2aec8)...
14 = HASH(0x1d2af40)...
15 = HASH(0x1d2afa0)...
2 = HASH(0x1d5a970)...
3 = HASH(0x1ae7d08)...Cut...
4 = HASH(0x1d2adb4)...Cut...
5 = HASH(0x1d36948)...Cut...
6 = HASH(0x1ae8248)...Cut...
7 = HASH(0x1ae8404)...Cut...
8 = HASH(0x1ae8734)...Cut...
9 = HASH(0x1ae8998)...Cut...
9 = HASH(0x1d2afdc)...Cut...
|
Так вот мне надо в новый файл сначала выкинуть строку "1 = '\n'" проверив ее, является ли она хешем, если нет то вывести ее в опр. формате, когда дело дойдет до строки "8 = HASH(0x1d2ae98)...", то при проверке на хеш, заходим в него, проверяем является ли "'define service{' = HASH(0x1d2aee0)..." хешем, если да то снова заходим в него, и т.д. пока не наткнемся на НЕ хеш. причем выводить строки мне надо по номерам(в данном случае с 1-7, потом всю внутрянку 8-ого (с 0 - 15), потом внутр 9 и т.д.
Что делать то я знаю, а вот как это писать понять не могу!!!
Хелп ми, плиз. |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Пт Июн 16 2006 12:17 Заголовок сообщения: |
|
|
Дык.. ну вон прямо тот код, который я написал, только там Код: | } elsif (ref eq "HASH") {
my %a = %$_;
Unparse($a{$_}, "$prefix{"."$_}") for sort {$a <=> $b} keys %a
} |
sort {$a <=> $b} дает еще и численную сортировку (по умолчанию сортировка по алфавиту - см отписание функции sort)
Чтобы отличить ссылку на хеш от литерала (ну .. просто строки) как раз и используется команда ref. в моем примере она без аргумента, потому что саму строку я предварительно закинул в $_ (переменные по умолчанию - страшное зло ) _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
|