Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> нужна помощь 
:(
    Опции темы
DooZ
Дата 14.4.2008, 22:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



задача следующая:

есть файл со словами (очень большой, например 500 мегабайт, или 10.000.000 слов, как пример)
мама смотрит в окно
моя книга очень интересная
книга и авто не совместимы

все слова в столбик

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

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

Код

foreach my $request (keys %request)
{
if ($keyword =~ /(?:^|\s+)$request(?:\s+|$)/i)
{
open(F, ">>$request");
print F "$keyword\n";
close(F);
}


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

в свою очередь во втором файле мы видим что нам нужны все строки где есть слово: "авто" и "книга"
т.е. мы должды записать строку: "книга и авто не совместимы" в файл: "авто"
И (!)
эту же строку записать в файл: "книга"

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

посоветовали сделать сначала выборку путем комманды: "cat $file|grep -P '(?:^|\s+)(?:окно|авто|книга)(?:\s+|$)' >tmp/complete"
и потом уже разбирать файл complete построчно
НО очень долго получается разбирать его

т.е. cat + grep работает очень быстро
а вот выборка по нужным запросом долго (файл в миллион строк, разбирается около часа)

т.е. получается в данном случае нам надо три запроса:
окно
книга
авто
т.е. если cat + grep насобирал миллион записей, то при выборке будет обработано 3.000.000 записей

у меня этих запросов сотни, соответсвенно кол-во выборок увеличивается не по детски =)

как быть? кто что подскажет?

можно в аську: 9603308 (можно за денежку, если действительно быстро будет работать, о цене договоримся)

заранее благодарю
PM MAIL   Вверх
arto
Дата 14.4.2008, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



grep "\\b$word\\b" ?
+ распарралелить по возможности
PM MAIL ICQ   Вверх
DooZ
Дата 14.4.2008, 23:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



поточнее можно?
мне надо каждую найденую строку У КАЖДОГО запроса записать в свой файл
т.е.
если в файле номер 1 есть строка:
ааа ббб ввв ггг ддд

а в файле 2 в котором нужные мне запросы есть два запроса:
ббб
ддд

надо записать в два файла эту строку
в файл: ббб
и в файл: ддд
PM MAIL   Вверх
arto
Дата 14.4.2008, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



1. поделить второй список по 20 слов, например.
2. запускать по 20 процессов grep с выводом в нужный файл
3. удалить пустые файлы.
4. простой греп быстрее, чем perl regexp
PM MAIL ICQ   Вверх
DooZ
Дата 14.4.2008, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



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

Добавлено через 2 минуты и 30 секунд
проблемма не у grep, а в том что много запросов нужных мне, и приходится перебирать массив (хеш) и работать с каждым запросом на каждой строке

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

Добавлено через 11 минут и 12 секунд
вот код тот что щас работает:

Код

#!/usr/bin/perl -w

use strict;

my %request;
my $request = "";

open(F, "request");

    while (my $request=<F>)
    {
    chomp($request);
    next if (!$request || $request eq "");
    $request{$request}++;
    }

close(F);

    foreach my $r (keys %request)
    {
    $request .= "$r|";
    }

$request =~ s/\|$//;
####################
my $grep = '(?:^|\s+)(?:'.$request.')(?:\s+|$)';
system("cat $file|grep -P '$grep' >complete");

open(F, "complete");

    while (my $keyword=<F>)
    {
    chomp($keyword);
    next if (!$keyword || $keyword eq "");

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

        foreach my $request (keys %request)
        {
            if ($keyword =~ /(?:^|\s+)$request(?:\s+|$)/i)
            {
            open(WRITE, ">>out/$request");
            print WRITE "$keyword\n";
            close(WRITE);
            }
        }
    }

close(F);

PM MAIL   Вверх
arto
Дата 14.4.2008, 23:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



тогда вам надо подготовить списки под задачу заранее.
PM MAIL ICQ   Вверх
DooZ
Дата 14.4.2008, 23:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



т.е. подготовить?

они и так подготовлены
в файле1, список строк на проверку
в файле2, список слов которые мне нужно выдирать из файла1, что тут не подготовлено?

или я чего-то не понимаю, или Вы меня smile
PM MAIL   Вверх
arto
Дата 15.4.2008, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



не понимаете, да.

например -- адреса всех слов в первом файле, с длиной.
тогда сможете сократить перебор по длине.
еще можете проиндексировать по первой букве.

делать это надо не сейчас, а когда собирается первый файл.
PM MAIL ICQ   Вверх
sir_nuf_nuf
Дата 15.4.2008, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



так...если хотим простое решение, то на мой взгляд их 2
в обоих случаях - 2 цикла , один в другом.

в первом проходим по всем строкам,  для каждой строки ищем ключи:

Код

open STRS, "<first" or die "no first";
open KEYS, "<second" or die "no second";
my @keys = <KEYS>;
chomp @keys;
my %handles = map {open my $fh, ">$_"; $_ => $fh } @keys;
my %regex = map {$_ => qr/$_/} @keys;
foreach my $str (<STRS>) {
    foreach my $key (keys %regex) {
        if ($str =~ $regex{$key}) {
            my $fh = $handles{$key};
            print $fh $str;
        }
    }
}

close STRS;
close KEYS;



или второй вариант - для каждого ключа полностью просматриваем файл с данными
Код

open STRS, "<first" or die "no first";
open KEYS, "<second" or die "no second";
my @keys = <KEYS>;
chomp @keys;
my %handles = map {open my $fh, ">$_"; $_ => $fh } @keys;
my %regex = map {$_ => qr/$_/} @keys;
foreach my $key (keys %regex) {
    seek(STRS, 0,0);
    foreach my $str (<STRS>) {
        if ($str =~ $regex{$key}) {
            my $fh = $handles{$key};
            print $fh $str;
        }
    }
}

close STRS;
close KEYS;


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

есть еще вариант - засунуть перебор шаблонов в регулярку:
Код

open STRS, "<first" or die "no first";
open KEYS, "<second" or die "no second";

my @keys = <KEYS>;
chomp @keys;
my %handles = map {open my $fh, ">$_"; $_ => $fh } @keys;
my $regex = "(" . join("|", @keys) . ")";
my $compiled = qr/$regex/;
foreach my $str (<STRS>) {
    if (my @matches = $str =~ /$compiled/g ) {
        foreach my $file (@matches) {
            my $h = $handles{$file};
            print $h $str;
        }
    }
}

close STRS;
close KEYS;

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


Если вам нужен _быстрый_ поиск по нескольким ключам - заведите новый топик и изучите алгоритмы =)


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
DooZ
Дата 15.4.2008, 01:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



2sir_nuf_nuf
первый вариант теряет всю скорость, если регекс делать таким:
(?:^|\s+)$_(?:\s+|$)
что ознатает что нужный запрос может быть
в начале, после него могут быть пробелы или конец текста
или в конце
или перед и после пробелы и т.д.

а так и надо искать, ибо твой вариант где просто $_ будет искать например:
запрос: машина

-> у меня есть машина (годится)
-> у друга есть машина (годится)
-> естьмашина (не годится, а твой вариант возьмет его!)

есть еще мысли как ускорить?
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 01:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



третий вариант очень быстрый, но в нем минус, если он встречает первое нужное слово в строке, то если даже в этой строке есть второй нужное слово, он его уже не запишет!
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



вроде заработал третий пример вот так:

    foreach my $str (<STRS>)
    {
        if ($str =~ /$compiled/igs)
        {
            foreach my $file (split(/\s+/, $str))
            {
            next unless (exists $handles{$file});
            my $h = $handles{$file};
            print $h $str;
            }
        }
    }

скорость на 160 запросах, и 100.000 строк файл первый, 1.5 секунды
первый пример справлялся за 60 секунд
PM MAIL   Вверх
sir_nuf_nuf
Дата 15.4.2008, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



насчет третьего варианта - ты не прав. \
там специально стоит модификатор g и поиск в списковом контексте.
так что третий вариант не будет останавливаться после первого совпадения.

(?:^|\s+)$_(?:\s+|$) -- на счет этого я не подумал.. действительно нужно искать слова целиком

только шаблон этот записывается так:
\b$_\b


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
DooZ
Дата 15.4.2008, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



а ты проверь третий пример, без моего добавления. он именно находит первое совпадение и все...
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



щас проверил четвертый вариант

Код

open(F, "request");

    foreach my $request (<F>)
    {
    chomp($request);
    next if (!$request || $request eq "");
    open my $fh, ">out/$request";
    $request{$request} = $fh;
    }

close(F);

open STRS, "base" or die "no first";

    foreach my $str (<STRS>)
    {
        foreach my $file (split(/\s+/, $str))
        {
        next unless (exists $request{$file});
        my $h = $request{$file};
        print $h $str;
        }
    }

close STRS;



работает на 100к базе при 158 запросах за 0.6 секунды
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



косяк в 4 варианте, нельзя использовать запросы более одного слова, иначе не найдет
PM MAIL   Вверх
amg
Дата 15.4.2008, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



DooZ, зачем Вы все время используете конструкцию foreach my $str (<STRS>) ...? Ведь при этом весь файл в виде массива будет помещен в оперативную память. А если ее не хватит? Сами же говорите -- файлы большие. Используйте лучше while (my $str = <STRS>) .... Файл будет обрабатываться построчно, и, может быть, даже быстрее.
PM MAIL   Вверх
sir_nuf_nuf
Дата 15.4.2008, 12:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



странно, у меня 3ий вариант работает нормально

файлы:

first:
Код

mama mila ramu
riki tiki tavi
tavi mama


second:
Код

mama
tavi



tavi:
Код

riki tiki tavi
tavi mama


mama:
Код

mama mila ramu
tavi mama



--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
yura_nev
Дата 15.4.2008, 13:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 28.12.2007

Репутация: нет
Всего: нет



Код

perl -ne 'BEGIN{open$h,"keys.txt";chomp&&open($k{" $_ "},">",$_)for<$h>;close$h;@w=keys%k;}$s=$_;s/\s+/ /;$_=" $_ ";for$w(@w){if(index($_,$w)>=0){$h=$k{$w};print $h $s}}' big_text_file.txt

keys.txt - файл слов, одна строка - одно слово
big_text_file.txt - файл для разбора

Цитата
здесь перебор ключей осуществляется движком regex. Не думаю, что он делает оптимизацию для поиска 
по нескольким ключам, скорее всего просматривает строку на наличие каждго ключа последовательно.
perlre
perldoc -f study
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 13:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



2amg - foreach не мой вариант, а вариант sir_nuf_nuf
мой пример (исходник) без этих циклов
PM MAIL   Вверх
amg
Дата 15.4.2008, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(DooZ @  15.4.2008,  13:59 Найти цитируемый пост)
2amg - foreach не мой вариант
Да, действительно, прошу прощения. 

yura_nev, Вы дискредитируете идею перловских однострочников smile 

Кстати, DooZ, мысль yura_nev использовать index для определения наличия слова в строке может быть плодотворной. Эта функция гораздо быстрее, чем регулярные выражения или split.
PM MAIL   Вверх
yura_nev
Дата 15.4.2008, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 28.12.2007

Репутация: нет
Всего: нет



amg, каким образом?
вообще говоря, мне просто лень было открывать редактор
PM MAIL   Вверх
sir_nuf_nuf
Дата 15.4.2008, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



Цитата(amg @ 15.4.2008,  14:26)
Цитата(DooZ @  15.4.2008,  13:59 Найти цитируемый пост)
2amg - foreach не мой вариант
Да, действительно, прошу прощения. 

yura_nev, Вы дискредитируете идею перловских однострочников smile 

Кстати, DooZ, мысль yura_nev использовать index для определения наличия слова в строке может быть плодотворной. Эта функция гораздо быстрее, чем регулярные выражения или split.

это мой вариант..
действительно, чтение в списковом громадных файлов в списковом контексте - не лучшая идея.
как то не подумал =(

идея строить индексы с помощью study  - великолепно =)

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





--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
GoDleSS
Дата 15.4.2008, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



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

#!perl

my $dict = 'dict2.txt';
my $dbf = 'db.txt';
my $output = 'output';

parse_long($dbf, $dict, $output);

sub parse_long {
    my ($dbf, $dict_link, $output) = (
        shift || return,
        get_dict(shift) || return,
        shift || '.'
    );

    my (%struct, $keyword);

    open(DBF, $dbf);
        while(<DBF>) {
            next if ($_ eq '');#удалить, если файл точно без пустых строк
            foreach $keyword (@$dict_link) {
                if ( index($_, $keyword)+1 ) {
                    push(@{ $struct{$keyword} }, $_);
                }
            }
        }
    close(DBF);

    foreach (keys %struct) {
        open(OF, ">$output/$_");
            print OF @{ $struct{$_} };
        close(OF);
    }
}

sub get_dict {
    my $file=shift;
    my @dict;
    open(DF, $file);
        while(<DF>) {
            chomp;
            push(@dict, $_);
        }
    close(DF);
    return \@dict;
}



Куча минусов, в том числе и регистрозависимость поиска.
Ну уж если важна скорость )
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
sir_nuf_nuf
Дата 15.4.2008, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



функция get_dict пишется проще

sub get_dict 
{
    open my $file "<<$_[0]" or die "for ever";
    my @strs = <$file>;
    chomp @strs;
    return \@strs;
}

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

примерно так:
$str = "mama mila lamu"

будет создан индекс букв:

a - 1,3,8,11
m - 0,2,5,12
i - 6
l - 7,10
u - 13

теперь когда мы будем искать подстроку "mu"

мы не будем просматривать строку с самого начала,
мы по индексу найдем , что "u" встречается в 13 позиции,
а потом проверим, что в 12 позиции есть буква "m"

вот примерно так работает study + regex

perldoc -f study =)



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


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
GoDleSS
Дата 15.4.2008, 23:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Цитата

sub get_dict 
{
    open my $file "<<$_[0]" or die "for ever";
    my @strs = <$file>;
    chomp @strs;
    return \@strs;
}

Не красиво оставлять открытыми потоки ввода/вывода ;)

Но 
Код

chomp @strs;

для меня новость, спасибо )

Цитата

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

примерно так:
$str = "mama mila lamu"

будет создан индекс букв:

a - 1,3,8,11
m - 0,2,5,12
i - 6
l - 7,10
u - 13

теперь когда мы будем искать подстроку "mu"

мы не будем просматривать строку с самого начала,
мы по индексу найдем , что "u" встречается в 13 позиции,
а потом проверим, что в 12 позиции есть буква "m"

очень сомневаюсь, что даже такая констукция, при малой длине строки и большом кол-ве этих строк, будет работать заметно быстрее, чем index/rindex.
Хотя... ...практика покажет smile

Цитата

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

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

Может я что-то упускаю?
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
sir_nuf_nuf
Дата 16.4.2008, 00:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



Цитата

Не красиво оставлять открытыми потоки ввода/вывода ;)

да не красиво =) по этому я и написал эту функцию так.
поверьте (проверьте) в этом случае хендлер закрывается автоматически при выходе из блока.
в этом фишка использования лексических переменных =)
здесь переменная my $file ссылка на объект IO::File
при выходе из блока мы потеряем ссылку на объект, perl вызовет его DESTRUCTOR и поток будет закрыт =)

я представляю себе такой алгоритм: 

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

Код

ааа
ааb
abc
b


дерево будет выглядеть так:
Код

          root
           /  \
         a     b
        /  \
      a     b
     /  \     \
   a     b    c


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

Если мы пришли в лист дерева то мы нашли ключ в строке, например root -> a -> b -> c соответсвует найденному ключу abc.
Запоминаем, что мы нашли определенный ключ, передвигаем позицию вперед на длину ключа.

В случае если мы не можем спускаться дальше, например нет пути root -> a -> b -> x, то мы увеличиваем позицию на 1 символ.

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


Возможно, что оптимизатор регулярных выражений и догадывается делать поиск таким образом для шаблонов вида 
ааа|ааb|abc|b

как видите - не совсем перебор. мы ищем все ключи сразу =)
такой алгоритм не удобно писать на perl - в нем поддержки посимвольной обработки строк ( о не говорите мне про split(//,"..."));

Это сообщение отредактировал(а) sir_nuf_nuf - 16.4.2008, 00:49


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
GoDleSS
Дата 16.4.2008, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Цитата

такой алгоритм не удобно писать на perl - в нем поддержки посимвольной обработки строк ( о не говорите мне про split(//,"..."));

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

Однако, используя perl также можно прийти к посимвольному чтению, достаточно пользоваться getc, [sys]read.
Сравнивать на эквивалентность односимвольных строк с помощью eq. В менее шустром варианте, опять же, с помощью index.
Для perl сие извращение, но возможность есть smile

Цитата

Возможно, что оптимизатор регулярных выражений и догадывается делать поиск таким образом для шаблонов вида 
ааа|ааb|abc|b

Сомневаюсь.

--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0749 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.