namazu-ml(avocado)


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: HTML detection



SHIOZAKI Takehiko <takehi-s@xxxxxxxxxxx> wrote:

>mknmzのロボット除けのところで、$DEFAULT_FILEが考慮されていないことに気づ
>きました。
>HTMLファイルの検出を何ヶ所も書くのも何なので、こっそりと(嘘)例のCGIのも
>含めてサブルーチンにしてみました。お試しください。

ありがたく使わせていただきます。

-- Satoru Takabayashi

[namazu:01621] の末尾に添付した Perl版わかち書きプログラムの改良版
です。

使い方

  1. まず最初に kakasidict を DBM化する (時間がかかります)
     % perl wakati.pl -i kakasidict
     % ls kakasidict.*
     kakasidict.dir kakasi.pag
  
  2. 一度 DBMを作ってしまえば後は普通に使うだけです
     % perl wakati.pl kakasidict < input > output

注意事項

  1. EUC-JPしか受け付けません
  2. 送り仮名の処理はしていません。

性能

  % time kakasi -w < manual.html > /dev/null 
  real    0m1.877s
  user    0m1.640s
  sys     0m0.240s
  
  % time perl wakati.pl kakasidict < manual.html > /dev/null 
  real    0m3.980s
  user    0m3.780s
  sys     0m0.200s

  どなたか高速化に挑戦してみませんか?


#!/usr/bin/perl
require 5.004;
use strict;
use IO::File;
use Fcntl;
use SDBM_File;
my $CHAR  = "(?:[\x21-\x7e]|[\xa1-\xfe][\xa1-\xfe])";
my $NONKANJI = "(?:[\x21-\x7e]|[\xa1-\xaf][\xa1-\xfe])";
my $KIGOU = "(?:[\xa1\xa2\xa6-\xa8][\xa1-\xfe])";
my $ALNUM = "(?:\xa3[\xa1-\xfe])";
my $CHOON    = "(?:[\xa1][\xbc])";
my $HIRAGANA = "(?:(?:[\xa4][\xa1-\xf3])|$CHOON)";
my $KATAKANA = "(?:(?:[\xa5][\xa1-\xf6])|$CHOON)";
my $KANJI    = "(?:[\xb0-\xfe][\xa1-\xfe]|\xa1\xb9)";
my %dict;

unless (defined($ARGV[0])) {
    print STDERR <<USAGE;
    usage: wakati [-i] <kakasidict>
       -i: convert  KAKASI dictionary into a DBM file
    example: cat hoge.txt | wakati kakasidict > kekka.txt

USAGE
    exit 1;
}

STDIN->autoflush(1);

if ($ARGV[0] eq "-i") {
    shift @ARGV;
    tie %dict, "SDBM_File", $ARGV[0], O_RDWR|O_CREAT, 0666 or
	    die "$!\n";
    load_dict($ARGV[0]);
    exit;
}

tie %dict, "SDBM_File", $ARGV[0], O_RDWR|O_CREAT, 0666 or
	    die "$!\n";

main();

sub main() {
    my $content = join('', <STDIN>);
    while (1) {
#	if ($content =~ /\G($KANJI(?:$KANJI|$HIRAGANA)*)(\s*)/gc) {
	if ($content =~ /\G($KANJI+)\s*/gc) {
	    print wakatize($1), $2 ? $2 : " ";
	} elsif ($content =~ 
		 /\G
		 ([\x21-\x7e]+|$HIRAGANA+|$KATAKANA+|$ALNUM+|$KIGOU+|\S+)
		 (\s*)
		 /gcx) 
	{
	    print $1, $2 ? $2 : " ";
	} elsif ($content =~ /\G(\s+)/gc) {
	    print $1;
	} else {
	    last;
	}

    }
}
untie %dict;

sub wakatize($) {
    my ($string) = @_;
    my $rest_string = $string;
    my @parts = ();

    if (length($string) <= 4) { # too short to wakatize
	return $string;
    }
    while (length($rest_string) > 0) {
	my $tmp = $rest_string;
	my $try = "";
	my $matched_part;

	# get the longest match
	while ($tmp =~ /\G($CHAR)/gc) { 
	    $try .= $1;
	    if (defined($dict{$try})) {
		$matched_part = $try;
	    } 
	}
	if (defined($matched_part)) {  # matched!
	    $rest_string =~ s/^$matched_part//;
	    push(@parts, $matched_part);
	} else {
	    last;
	}
    }
    push(@parts, $rest_string) if $rest_string;
    join(' ', @parts);  # return with value
}

sub load_dict($)
{
    my ($dictfile) = @_;
    my ($fh) = new IO::File;

    $fh->open("$dictfile") || die "$!: $dictfile\n";
    while (<$fh>) {
	next if /^;/;

	/^(.*?) +(.*)$/;
	if (defined($dict{$2})) { # conflict
#	    print STDERR "'$2 ($1)' is already defined as '$2 ($dict{$2})'!\n";
	    next;
	}
	$dict{$2} = 1;
    }
}