コマンドラインから goo辞書検索

良く本を読んでいて分からない言葉に出くわすと,goo辞書で検索して意味を調べるのですが,わざわざブラウザから検索して,クリックして。。。の作業が毎回煩わしかったので,コマンドラインからサクッと検索できるスクリプトを作成しました。

昔に作成したやつで,現在 Perl に移植したいと考えてるんですがめんどくせ〜!

使い方。

$ dic foo
 1:  Foo・chow
 2:  food
 3:  Food 4 Less Holdings
 4:  food additive
 5:  Food and Agriculture Organization
 6:  Food and Drug Administration
 7:  food bank
 8:  food basket
 9:  food chain
10:  food court
> 2
━━ n. 食物; 食品; 養分; (心の)かて; 餌食(えじき) *1.

Food 4 Less Holdings 米国の小売会社.
food additive 食品添加物.
Food and Agriculture Organization (the 〜) (国連)食糧農業機関 *2.
Food and Drug Administration 〔米〕 食品医薬品局 *3.
food bank 〔米〕 (貧困者への)食糧給付所.
food basket 穀倉地帯.
food chain 【生物】食物連鎖.
food court (建物・敷地内の)ファスト・フード店街.
food ccle 【生物】食物環 *4.
food・ie, food・y ━━ n. 〔話〕 食い道楽の人; 食通.
food labeling (法的に義務化されている缶詰などの)内容表示.
food poisoning 食中毒.
food processing (food processorでの)食材の下ごしらえ.
food processor フードプロセッサー *5.
food stamp 食料切符 *6.
food・stuff 食糧; 栄養素.
food web 【エコロジー】食物網(もう).

ソース:

#!/usr/bin/env ruby
require 'cgi'
require 'nkf'
require 'optparse'
require 'mechanize'
require 'hpricot'
require 'open-uri'

############################################################
#
# Please set following below parameter according to
# your environment
#
# LOCAL_CHAR_CODE = ("jis" | "sjis" | "euc" | "utf8")

LOCAL_CHAR_CODE = "utf8"

############################################################

REMOTE_CHAR_CODE = "euc"

STR2CODE = {
  "JIS" => NKF::JIS,
  "SJIS" => NKF::SJIS,
  "EUC" => NKF::EUC,
  "UTF8" => NKF::UTF8,
}

unless STR2CODE.has_key?(LOCAL_CHAR_CODE.upcase)
  $stderr.puts("[!] Unexpected value: local_char_code = #{LOCAL_CHAR_CODE}")
  exit 0
end

CODE = {
  :local => STR2CODE[LOCAL_CHAR_CODE.upcase],
  :remote => STR2CODE[REMOTE_CHAR_CODE.upcase],
}

CODE2OPT = {
  NKF::JIS => 'j',
  NKF::SJIS => 's',
  NKF::EUC => 'e',
  NKF::UTF8 => 'w',
}

NKF_OPT = {
  :l2r => "-#{CODE2OPT[ CODE[:local ] ].upcase}#{CODE2OPT[ CODE[:remote] ]}",
  :r2l => "-#{CODE2OPT[ CODE[:remote] ].upcase}#{CODE2OPT[ CODE[:local ] ]}",
}

def encode(direction, str)
  NKF.nkf(NKF_OPT[direction], str)
end

def print_help_and_exit(status)
  puts "Usage: #$0  searchword\n"
  exit(status)
end

def search(url)
  doc = Hpricot(open(url))
  elm = doc.search("div.mainlst").first
  text = encode(:r2l, elm.to_plain_text)
  text.gsub(%r!\[(img:|http|/).*?\]\??!, "").sub(/\n.*\z/, "")
end

def ascii?(str)
  /^[a-zA-Z]+$/ =~ str
end

if ARGV.empty? || /^-{1,2}h/ =~ ARGV[0]
  print_help_and_exit(0)
else
  search_word = ARGV.shift
  kind = if ascii?(search_word) then 'ej' else 'jn' end
  enc_search_word = encode(:l2r, search_word)
  esc_search_word = CGI.escape(enc_search_word)
end

top_page_url = 'http://dictionary.goo.ne.jp/'
agent = WWW::Mechanize.new
agent.user_agent_alias = 'Linux Mozilla'
top_page = agent.get(top_page_url)
search_form = top_page.forms.name('dict').first
search_form.fields.name('MT').value = enc_search_word
word_list_page = agent.submit(search_form, search_form.buttons.first)

links = []
found_links = []
nfound = 0
HREF_RE = %r!search\.php\?MT=#{esc_search_word}&kind=#{kind}&mode=0&base=1&row=!
word_list_page.links.each do |link|
  if link.href =~ HREF_RE
    #abs_path = top_page_url + link.href
    abs_path = link.href
    unless links.include?(abs_path)
      links.push(abs_path)
      found_links[nfound] = {
        :text => NKF.nkf("-ww", link.text), :url => abs_path
      }
      nfound += 1
    end
  end
end

index = 0
case nfound
when 0
  puts "- Nothing found"
  exit 0
when 1
  puts found_links[index][:text]
  puts search(found_links[index][:url])
else # nfound > 1
  found_links.each_with_index do |link, index|
    printf("%2d: %s\n", index + 1, link[:text])
  end
  loop do
    print "> "; $stdout.flush
    begin
      index = gets.chomp.to_i - 1
    rescue SignalException
      exit
    end
    if index.between?(0, found_links.size - 1)
      puts search(found_links[index][:url])
      break
    else
      $stderr.puts "[!] Range of expexted value: 1 <= value <= #{nfound}"
    end
  end
end

*1:for

*2:略 FAO

*3:FDA

*4:food chainの総体

*5:電動調理器具

*6:低所得者に対して政府が発行する食料引き換え券