古い記事
ランダムジャンプ
新しい記事
入力テキストに辞書の語が含まれているかどうか調べるタスク。
入力テキストの文字位置をずらしながら、各位置で正規表現による「辞書引き」を行い漏れなく調べる方針。

■サンプルコード(regexdic.pl):
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use open ':utf8';
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";

my $dic_fn = shift @ARGV;

my %token;
open(my $fh, "<:utf8", $dic_fn) or die;
while (<$fh>) {
    chomp;
    next if /^\s*$/;
    my ($k, $c)  = split(/\t/, $_, 2);
    $token{length($k)}{$k} = $c;
}
close($fh);

my %pat;
foreach my $i (keys %token) {
    $pat{$i} = join("|", keys %{$token{$i}});
}

while (<>) {
    print "> $_";
    chomp;
    next if /^\s*$/;
    my $s_ref = get_matched_strings(\%pat, $_);
    print join("\n", map {"$_\t".$token{length($_)}{$_}} sort keys %$s_ref)."\n";
}

sub get_matched_strings {
    my ($pat_ref, $text) = @_;
    my %match;
    for (my $i = 0; $i < length($text); $i++) {
	foreach my $len (keys %{$pat_ref}) {
	    $match{$1}++ if $text =~ /^.{$i}($pat_ref->{$len})/;
	}
    }
    return \%match;
};

■辞書(aiueo.dic):スペース連続はタブ。
あいう  r:aiu
あい    r:ai,k:愛
いえ    r:ie,k:家
いうえ  r:iue
うあい  r:uai
えあ    r:ea
おい    r:oi,k:甥

■実行例:
% echo 'あいうえおい' | ./regexdic.pl aiueo.dic
> あいうえおい
あい    r:ai,k:愛
あいう  r:aiu
いうえ  r:iue
おい    r:oi,k:甥

ちゃんとした実装にはほど遠いが、急ぎのときのコピペ用に。

文字列長ごとに正規表現を分けているのは、辞書に「あいう」「あい」がある場合に、入力テキスト「あいうえお」で両方にマッチさせるため。事前処理で「あいう」に「あい」が含まれるという情報を持たせて longest のみ得るという方式なら分けなくてもよいがちょっと面倒。なお、longest のみを得る場合は下記のようなパターンを作れば良い。
$pat_all = join("|", sort {length($b) <=> length($a)} keys %token_all);

入力文字列を一文字ずつずらしながらマッチさせているのは、辞書に「あいう」「いうえ」がある場合に、入力テキスト「あいうえお」で両方にマッチさせるため。

ref.
- [を] 正規表現でCommon Prefix Search [2007-05-15-1]
- [を] SUFARY.pm で Longest Common Prefix Search[2007-05-15-5]