1

「ab」、「ef」、「ab ef」などを含むキーワードファイルがあるとしましょう(実際には、さらに1000のエントリがあります)。各キーワードがどのページで発生しているかを調べたい

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 ]

私はこれを非常に非効率的に行う方法を知っています。ファイルを長い文字列に丸呑みします。小文字にします。ページに分割します。ページごとに、各 (小文字の) キーワード エントリを正規表現して、ページに表示されるかどうかを確認します。もしそうなら、私のキーワードをキーとして含むハッシュの最後にページ番号を追加してください。難しいことではありませんが、非常に非効率的です。私のアルゴリズムは、洗練された perl アプローチというよりは、C アプローチのように見えます。

悲しいかな、私はより良い代替案を考えることはできません. 最初にメインファイルをハッシュに読み込むことさえできません。スペースで区切られた複数の単語のキーワードの可能性により、この洗練されていない悪いロジックが作成されるためです。

おそらくperlはこれには間違ったツールですか?!

4

3 に答える 3

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;
于 2013-10-01T22:57:20.447 に答える
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
于 2013-10-01T22:37:22.337 に答える
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
        ];

あなたのサンプルに基づいています。

于 2013-10-01T22:29:07.830 に答える