古い記事
ランダムジャンプ
新しい記事
SUFARY に付属している sang というプログラムの Perl 版「sang.pl」を作りました。
オリジナルCコード(sang.c)に書いてある説明を改変して載せておきます。
使い方は同じです。

sang.pl  ---  Suffix Array を用いて N-gram 統計をとるプログラム

USAGE   sang.pl -n NUM -t NUM FILENAME
OPTION
-n NUM : NUM で n-gram の n を指定する。
-t NUM : threshold: NUM以下の頻度のものは表示しない

n-gram には改行は含まれない。

[実行例]
% cat test
ABCBACABBAACABCABCACABACABBACBACACAAABACCAB
% makeary -q test                 ● arrayファイルの作成
% sang -n 6 -t 1 test             ● 6-gram で頻度が 1 より大きいものを表示
2 ACABBA
2 BACABB
% ./sang.pl -n 3 -t 4 test        ● trigram で頻度が 4 より大きいものを表示
6 ACA
5 BAC
6 CAB

■コード(sang.pl):
#!/usr/bin/perl
use strict;
use warnings;
use SUFARY;
use Encode;
use Getopt::Std;
use utf8;
use open ':utf8';
binmode STDOUT, ":utf8";

my %opts = ();
getopts("n:t:", \%opts);
my $ng = $opts{n} || 4;
my $threshold = $opts{t} || 3;
my $fn = shift @ARGV;
my $sa = SUFARY->new($fn);

my $n_ctr = 0;
my @ktoks = ();
for (my $i = 0; $i < $sa->{arraysize}; $i++) {
    my $pos = $sa->get_position($i);
    my ($from, $len) = $sa->get_line_info($pos);
    my $s = $sa->get_string($pos, $from + $len - $pos);
    $s =~ s/^([^\n]+)\n.*$/$1/;
    my @ttoks = map {Encode::decode_utf8($_)}
       ($s =~ m{([\x00-\x7f]|[\xC0-\xDF][\x80-\xBF]|
       [\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})}gsx);
    if (cmp_tok(\@ktoks, \@ttoks) >= $ng) {
       $n_ctr++;
    } else {
       output();
       $n_ctr = 1;
    }
    @ktoks = @ttoks;
}

output() if $n_ctr >= 1;

sub output {
    return if $n_ctr <= $threshold;
    print "$n_ctr ".join("", @ktoks[0..($ng-1)])."\n";
}

sub cmp_tok {
    my ($k_ref, $t_ref) = @_;
    my $i;
    for ($i = 0; $i < @$k_ref and $i < @$t_ref; $i++) {
       last if $k_ref->[$i] ne $t_ref->[$i];
    }
    return $i;
}

■実行例:
インデックス作成。
対象ファイルは utf-8。
mkipu8.pl[2007-06-10-3]を使う。
% ./mkipu8.pl a.txt > a.txt.ary
% mkary -so a.txt
N-gram カウント。
4-gram で頻度は3よりも大きいものを出力。
% ./sang.pl -n 4 -t 3 a.txt 
4 100円
5 「ぬんな
10 ぬんなり
4 ました。
4 まったり
5 んなり」

ref.
- SUFARY 臨時復旧ページ http://ta2o.net/tools/sufary/
(SUFARYの入手はここから。)
- [を] SUFARY用インデクサのPerl版の雛形[2007-06-10-3]
(mkipu8.pl のソースはここに。)
- [を] 自分マイニング! - Blogでよく使うフレーズは?[2005-01-18-3]
(sang を使ったデータマイニング例。)