真正的索引--- perl中的多重匹配

时间:2013-10-01 22:10:55

标签: string perl

假设我有一个关键字文件,包含,说“ab”,“ef”,“ab ef”(现实生活:另外数千个条目)。我想查看每个关键字正在发生的页面

page 0
ab
gg
^L
page 1
ab ef
^L
page 2
Ab
ef
[another thousand pages, 2 million words, each ^L separated]

我想回来

ab => [ 0,1,2 ]
ef => [ 1,2 ]
ab ef => [ 1 ]

我知道如何非常低效地完成这项工作。将文件粘贴成长字符串。小写它。将其拆分成页面。对于每个页面,正则表达式每个(小写)关键字条目,以查看它是否出现在页面上。如果是这样,那么在包含我的关键字作为键的哈希的末尾添加页码。并不难,但效率低下。我的算法看起来更像是一种C方法,而不是一种优雅的perl方法。

唉,我想不出更好的选择。我甚至不能首先将主文件读入哈希,因为空格分隔的多词关键词的可能性会使这个不优雅的错误逻辑。

也许perl是错误的工具?!

3 个答案:

答案 0 :(得分:4)

其他答案采用了不必要的复杂手段。这个问题的关键是要理解我们可以将结束$/的行设置为我们喜欢的任何内容。 ^L代表换页\f

use strict; use warnings;
use List::MoreUtils qw/uniq/;

my %keywords;
local $/ = "\f";  # set the input record separator (aka. line end) to form feed

while (<>) {
  chomp; # remove the \f
  my ($page, $body) = split /\n/, $_, 2;    # seperate the page header
  my $page_no = ($page =~ /([0-9]+)/) ? $1  # extract the page number
                : die "Header did not contain a number:\n$page\n";

  # split body into lines, and lines into words. Keep only unique KWs:
  my @words = uniq map { $_, split } split /\n/, lc $body;
  # Map KWs to an array of page №s.
  push @{ $keywords{$_} }, $page_no for @words;
}

# Output the data:
use Data::Dumper;
print Dumper \%keywords;

答案 1 :(得分:1)

这对Perl来说非常完美;只是看看它的另一种方式。使用每个关键字,将当前页面添加到该单词的页面列表中。如果这是我们见过的第一个,请创建单词的页面列表。

use strict;
use warnings;

use Data::Dumper;


my %keywords = ();
my $page = 0;

while (<>)
{
    chomp;  # remove newline

    if (/^page \d+$/)   # skip "page 0", etc.
    {
        next;
    }
    elsif (/^\l$/)      # ctrl-L: new page
    {
        ++$page;
    }
    else
    {
        my $word = lc($_);

        addWord($word);

        if ($word =~ /\s/)
        {
            my @parts = split(/\s+/, $word);

            for my $part (@parts)
            {
                addWord($part);
            }
        }
    }
}

print Dumper(%keywords);


sub addWord
{
    my ($word) = @_;

    # haven't seen this word? start an empty page list
    if (! defined($keywords{$word}))
    {
        $keywords{$word} = [];
    }

    # add current page to the word's list
    push @{ $keywords{$word} }, $page;
}

打印:

$VAR1 = 'ef';
$VAR2 = [
          1,
          2
        ];
$VAR3 = 'gg';
$VAR4 = [
          0
        ];
$VAR5 = 'ab';
$VAR6 = [
          0,
          1,
          2
        ];
$VAR7 = 'ab ef';
$VAR8 = [
          1
        ];

根据您的样本。

答案 2 :(得分:1)

完美地使用perl。

输出以下内容:

ab => [ 0,1,2 ]
ab ef => [ 1 ]
ef => [ 1,2 ]
gg => [ 0 ]

代码:

#!/usr/bin/env perl

use warnings;
use strict;

main();
1;

sub main {
    my $data = {};
    my $page = 0;
    while (<DATA>) {
        chomp;
        next if /\A\^L/;
        if (/\Apage (\d+)/) {
            $page = $1;
        } else {
            my $line = lc($_);
            $data->{$line}->{$page}++;
            for (split /\s/, $line) {
                $data->{$_}->{$page}++;
            }
        }
    }

    for my $keyword (sort keys %$data) {
        my @pages = sort {$a <=> $b} keys %{$data->{$keyword}};
        print $keyword . ' => [ ' . join(',',@pages) . ' ]' . "\n";
    }
}

__DATA__
page 0
ab
gg
^L
page 1
ab ef
^L
page 2
Ab
ef