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


Автор: study 3.5.2006, 08:58
Привет всем!
Народ у меня такой вопрос. Мне надо проанализировать файл, при обнаружении определенный строки (например start-111), начинать подсчет других определенных строк, а при обнаружении строки stop-111, завершать сбор и выводить накопленную статистику в файл. Возможна ситуация, когда до завершения сбора придет другой start-222...

Можно ли сохранять в хэшь или в массив (многомерный) эти данные, а по приходу stop удалять этот параметр из хэша, т.е. (a, @b), где a - парамертstart, а массив b - строки? 

Автор: GoodBoy 3.5.2006, 09:13
study, что-то такое тебе надо?

Код
if (open (FL, "data.dat")) {
    my %hash = ();
    while (<FL>) {
        if ($_ =~ /start-(\d+)/) {  # попалась строка вида "start-цифры"
            @{$hash{$1}} = ();   # объявить массив в хэше
        } elsif ($_ =~ /stop-(\d+)/) {  # попалась строка вида "stop-цифры"
            my $num = $1;

            # сделать что надо с массивом  @{$hash{$num}}

            delete $hash{$num};  # удалить обработанный массив из хэша
        } else {
            my $str = $_;
            # сделать что надо со строкой $str

            push(@{$hash{$num}}, $str);
        }
    }
} else {
    print "Не могу открыть файл - $!";
}
 

Автор: study 3.5.2006, 09:39
спасибо GoodBoy, сейчас попробую 

Автор: study 4.5.2006, 09:47
Привет ещё раз!

Народ, а нельзя ли это как-нибудь оптимизировать, может не через хеши делать, а то слишком долго считает?  smile  

Автор: GoodBoy 4.5.2006, 09:52
оптимизировать можно вот так:

Код
open (FL, "data.dat") || die "Не могу открыть файл - $!";
my @lines = <FL>;
close FL;
my %hash = ();
while my $line (@lines) {
    if ($line =~ /start-(\d+)/) {  # попалась строка вида "start-цифры"
        @{$hash{$1}} = ();   # объявить массив в хэше
    } elsif ($line =~ /stop-(\d+)/) {  # попалась строка вида "stop-цифры"
        my $num = $1;

        # сделать что надо с массивом  @{$hash{$num}}

        delete $hash{$num};  # удалить обработанный массив из хэша
    } else {
        # сделать что надо со строкой $line

        push(@{$hash{$num}}, $line);
    }
}
 

Автор: sharq 4.5.2006, 11:23
GoodBoy, зачем ты читаешь в массив, а потом его перебераешь, это лишнее, много памяти тратится, особенно если файл большой.
Плюс отказываемся от старого стиля работы с файлами, а именно - от глобов и отказаться от лишних переменных - например, $line заменить на $_.
Поэтому:
Код

my %hash;
open (my $fl, '<', 'data.dat') || die "Не могу открыть файл - $!";
while (<$fl>) {
    chomp;
    ...
}


Плюс можно переписать через ссылки, чтобы все было оптимально.
А на счет алгоритма - я не смотрел smile

 smile     

Автор: nitr 4.5.2006, 11:25
Для работы с большими файликами лучше использовать tie

Добавлено @ 11:26 
На крайняк как DB_FILE... здесь уже писалось об этом...

Добавлено @ 11:30 
смотри http://forum.vingrad.ru/index.php?showtopic=88133&view=findpost&p=677032
и http://forum.vingrad.ru/index.php?showtopic=88133&view=findpost&p=676917 

Автор: GoodBoy 4.5.2006, 11:32
sharq, уважаемый, ты взял скелет из моего сообщения (второго от начала этой темы). Для чего это было сделано, можешь мне пояснить? 

Автор: sharq 4.5.2006, 12:53
GoodBoy
я оптимизировал приведенный тобой код, т.к.
Цитата(study @  4.5.2006,  10:47 Найти цитируемый пост)
нельзя ли это как-нибудь оптимизировать

А логику работы я не оптимизировал, т.к. не разбирал и твой вариант вполне рабочий!

Или тебе не понравилась моя оптимизация?  smile


 smile 
  

Автор: Kannabismus 4.5.2006, 13:33
Цитата(sharq @ 4.5.2006,  11:23)
Плюс отказываемся от старого стиля работы с файлами, а именно - от глобов...

Аргументируй, пожалуйста 

Автор: sharq 4.5.2006, 13:54
Kannabismus, в книле Ларри Уолла есть маленькая пометка об этом.
А вот в книге Intermediate Perl (вышла совсем недавно - март 2006, авторы:  brian d foy, Tom Phoenix, Randal L. Schwartz) отлично написано.

Ну а если нет под рукой книг, то вот:
в версии perl 5.6 появилась возможность в качестве файлового дескриптора использовать обыкновенный скалярную переменную,
незаводя для этого глоб, который может быть уже занят. Переменная определяется в open и что самое полезное - можно не закрывать файл (если нет необходимости!), то сборщик мусора perl сам все сделает. Так, например, в данном примере, close $fh - излишне!

Всем советую полистать приведенные выше книги, т.к. они действительно полезны, но не заменяют perldoc, а дополняют.
Плюс книга Perl Best Practics Damian Conway.

 smile  

Автор: GoodBoy 4.5.2006, 14:50
Цитата(sharq @  4.5.2006,  13:53 Найти цитируемый пост)
Или тебе не понравилась моя оптимизация?

Ты "оптимизировал" мой код вернув его к первоначальному варианту!!! 

Автор: sharq 4.5.2006, 15:01
GoodBoy, т.к. первоначальный вариант, твой лучше, чем второй.
Но мой вариант все-таки отличается от первого твоего + я посоветовал использовать ссылки (например, вместо %).

 smile  

Автор: GoodBoy 4.5.2006, 15:34
Цитата(sharq @  4.5.2006,  16:01 Найти цитируемый пост)
я посоветовал использовать ссылки 

Что ты этим хочешь сказать?

Что вместо
Код
my %hash = ();

использовать
Код
my $hash = {};

??

и, типа,
Код
@{$hash{$1}}

будет чем-то отличаться от
Код
@{$hash->{$1}}

??

Или что? 

Автор: Kannabismus 5.5.2006, 15:03
Цитата
Kannabismus, в книле Ларри Уолла есть маленькая пометка об этом.

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

Автор: nitr 5.5.2006, 15:11
Kannabismus, сказано же, что всё сам... это если в коде явно надо, то естественно, а это новый стиль, он не может стать хуже smile Ларри неидиот smile)) а если нравится старый, то юзай его smile 

Автор: sharq 5.5.2006, 17:06
Kannabismus
Цитата(Kannabismus @  5.5.2006,  16:03 Найти цитируемый пост)
в этом случае можно не закрывать файл, но это плохой стиль программирования. 
Все открытые хэндлы надо закрывать явно.  

Объяснять несколько раз я не собираюсь, не нравится - программируй как хочешь...

GoodBoy, не только.
Почитай perldoc perlref и perldoc perlreftut, сравни, потестируй, посмотри сколько памяти тратится и т.д.  

Автор: Kannabismus 5.5.2006, 20:41
Не "open my" плохо, а незакрывать хэндлы! Объяснять несколько раз я не собираюсь smile 

Автор: korob2001 5.5.2006, 21:14
Дескрипторы всегда можно было не закрывать, но это считается плохим стилем. Зачем держать открытым дескриптор, если он больше не используется? Это допустимо только в том случае, если у тебя подпрограмма открывает файл, что-то делает с ним и на том её выполнение заканчивается. Например:
Код
sub save_to_file {
    my $message = shift;
    open my $fh, ">>", "messages.txt" or die $!;
    print $fh $message . "\n";
}

Здесь дескриптор закрывать не обязательно, так как он сразуже уничтожается, как только сделана запись в файл, т.е. закончилась лексическая область видимости переменной объявленной как my, в нашем случае $fh. Но  если нужно ещё что-то сделать, в теле подпрограммы и оно не имеет прямого отношения к фалу, то помоему гораздо разумнее закрыть его явно. Например:
Код
sub read_file {
    open my $fh, "<", "messages.txt" or die $!;
    print while <$fh>;
    close $fh;
    print <<"    MESS";
    Зачем здесь нужен открытый дескриптор
    когда его можно освободить?
    MESS
}

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

Автор: sharq 6.5.2006, 17:13
Kannabismus, читай внимательно, что я написал. 
Хендел нужно закрывать тогда, когда это действительно необходимо!
А в приведенном выше примере - это необходимость отпадает!



 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)