さわだのノート

書籍のお仕事に役立つかもしれない思いつきを記録しています。

RSS: 記事の更新情報 Rss Feed

続・Vimで国語辞典を見る(同音異義語 対応版)

先ほど作った、Yahoo!辞書の国語辞典を閲覧するためのVimScriptですが、同音異義語や同じ表記だけど違う読みの語に対応しないのがどうもなあ……と感じ、ちょっと手を入れてみました。
http://takepierrot.hatenablog.jp/entry/2012/06/03/054938

ちょっと長くなってしまいましたが、以下がスクリプトになります。

" 出力用のバッファの管理
function! Jiten_Window()
  if !exists('s:bufnr')
    let s:bufnr = -1  " A number that doesn't exist.
  endif
  if !bufexists(s:bufnr)
    split
    edit `='[kokugo jiten output]'`
    let s:bufnr = bufnr('%')
    nnoremap <buffer> q <C-w>c
    nnoremap <buffer> <CR> :call CallDic()<CR>
    nnoremap <buffer> K :call CallRuigigo()<CR>
    setlocal bufhidden=hide buftype=nofile noswapfile nobuflisted
    setf txt
  elseif bufwinnr(s:bufnr) != -1
    execute bufwinnr(s:bufnr) 'wincmd w'
  else
    split
    execute 'buffer' s:bufnr
  endif
  normal ggdG
endfunction

" 国語辞典をチェック
fun! CallDic()
  if getreg('z') == ''
    normal viw"zy
  endif
  let s:str = getreg('z')
  call Jiten_Window()
  call Dic_check_itiran(s:str)
  call setreg('z', '')
endf
nnoremap <Leader>lk :call CallDic()<CR>

function! Dic_check_itiran(str)
perl << EOF
use utf8;
use URI;
use URI::QueryParam;
use Web::Query;
use Encode;

my $keyword = decode_utf8(VIM::Eval('a:str'));
if ($keyword =~ /^\d+$/) {
  VIM::DoCommand("call Dic_check_input($keyword)");
  return;
}

my (@id_list, @words);
my $page = 1;

for my $i (0 .. 20) {
  my $uri_itiran = URI->new('http://dic.search.yahoo.co.jp/dsearch');
  $uri_itiran->query_form(
    stype   => 'exact',
    p       => $keyword,
    dic_id  => 'dic_jj',
    b       => $page + $i * 10,
  );

  my $itiran = wq($uri_itiran)->find('div.result-r ol[start]');
  if ($itiran->find('li')->text) {
    $itiran->find('li')->each(sub {
        my ($num, $wq) = @_;
        my $uri = URI->new($wq->find('a')->attr('href'));
        push @words, $wq->find('h3')->text;
        push @id_list, $uri->query_param('index');
      });
  } else {
    last;
  }
}

if (scalar @id_list == 1) {
  my $num = shift @id_list;
  VIM::Msg($num);
  $num = sprintf '%d', $num;
  VIM::DoCommand("call Dic_check_input($num)");
} elsif (scalar @id_list == 0) {
  $main::curbuf->Set(1, "「$keyword」に該当する文字列は辞書にはありません");
} else {
  my @list;
  push @list, sprintf("%-8d[id]    %s", $id_list[$_], $words[$_]) for 0 .. $#id_list;
  $main::curbuf->Append(0, @list);
}
EOF
endfunction


fun! Dic_check_input(str)
perl << EOF
use utf8;
use URI;
use Web::Query;
use Encode;

my $uri_result = URI->new('http://dic.yahoo.co.jp/dsearch');
my $numeric = sprintf '%08s', decode_utf8(VIM::Eval('a:str'));;
$uri_result->query_form(
  dtype => 0,
  index => $numeric,
);
my $wq = wq($uri_result)->find('div.content-detail');
my $title = $wq->find('h1')->text;
my $html = $wq->find('table.d-detail')->html;
$html =~ s|<br />|\\n|g;
my $descr = Web::Query->new_from_html($html)->text;
$descr =~ s/(\\n)+/\n/g;
$descr =~ s/^ //mg;
$descr =~ s/^([1-9])/[$1]/mg;
my $honmon = $title . "\n" . $descr;
$main::curbuf->Append(0, split(/\n/, $honmon));
EOF
endf

同音異義語などの語句を検索すると、このように候補の語句が一覧表示されます。
f:id:takepierrot:20120603113409j:plain
IDの数字上でReturnキーを押すと、目的の語句の意味が確認できます。

このIDの数字、実は0で埋める8桁固定長なのですが、数字の頭に0がついた状態でVimScriptに評価させると、数字を勝手に変換しやがる場合があります。VimScript内で数字をほかの関数に渡すときは、「sprintf '%d', $num」で評価して余計な0をとっておく。URIモジュールでクエリを作るときは「sprintf '%08s', $num」で評価して0を追加するという感じに対処するのが安全みたいです。