掲示板に検索機能をつける:3. 独自フィルタを作成する

Hyper Estraierでは、そのままでは掲示板のデーターを読ませることができませんので、読ませるためにフィルターを作成します。

掲示板のデーター・フォーマット

私が使っている掲示板スクリプトのデーター・フォーマットは次のようになっています。

ハンドル名<>メールアドレス<>投稿日<>本文<>スレッドタイトル
ハンドル名<>メールアドレス<>投稿日<>本文<>
ハンドル名<>メールアドレス<>投稿日<>本文<>

1スレッド1ファイルで、1つのレスが1行に格納されています。ハンドル名などが“<>”という文字で区切られていて、最初の行にだけスレッドタイトルが格納されています。改行はHTMLの“br”タグになっています。その他にもHTMLのタグが入っている可能性があります。なお、キャップ(トリップ)がついている場合には、ハンドル名部分が次のようになります。

ハンドル名 </b>キャップ<b><>メールアドレス<>投稿日<>本文<>

たとえば、次のようなスレッドを考えてみます。

ゲームの話しよう
1 名前:よくある名無しさん [sage] 投稿日:2009/07/08(水) 01:22:33
  ゲームの話しようぜ!

2 名前:よくある名無しさん [] 投稿日:2009/07/08(水) 08:17:28
  しようしよう

3 名前:RPG名無しさん [sage] 投稿日:2009/07/10(水) 21:45:16
  ゲームって面白いよね。
  最近ドラクエやってる。

このスレッドのデーターは次のように格納されています。

よくある名無しさん<>sage<>2009/07/08(水) 01:22:33<>ゲームの話しようぜ!<>ゲームの話しよう
よくある名無しさん<><>2009/07/08(水) 08:17:28<>しようしよう<>
RPG名無しさん<>sage<>2009/07/10(水) 21:45:16<>ゲームって面白いよね。<br>最近ドラクエやってる。<>

Hyper Estraierで読み込めるようにするためのフィルタ

Hyper Estraierが扱える文書フォーマットは次の4種類です。

  • プレーンテキスト
  • HTML
  • MIME(電子メール)
  • 文書ドラフト

他のデーター形式の場合、上記のどれかの形式に変換することで、Hyper Estraierで扱えるようになります。変換するプログラムを「フィルタ」と呼びます。
Hyper Estraierに付属のフィルタは、インストールしたディレクトリ(私の場合は$HOME)のshare/hyperestraier/filterの下に“estfx〜”という名前で格納されています。私の環境には次のフィルタがインストールされていました。

フィルタ名 変換内容
estfxasis 何もしない(as is)
estfxmantotxt man page → プレーンテキスト
estfxmsotohtml Word/Excel/PowerPoint → HTML
estfxpdftohtml PDF → HTML
estfxxdwtotxt DocuWorks → プレーンテキスト

これらは引数を1つまたは2つとるコマンドです。最初の引数は入力ファイル名、2つ目の引数は出力ファイル名になります。出力ファイル名が指定されない場合には、標準出力に出力します。

独自フィルタを作成する

以上をふまえ、掲示板データーを変換するフィルタを作成しました。データーにはHTMLのタグが入っているため、HTML形式に変換することにします。名前は「estfxbbstohtml」にしました。ファイルのエンコーディングはUTF8Nにしています。

#!/usr/bin/env ruby

$KCODE = 'u'
require 'kconv'

def main
  case ARGV.length
  when 0
    $stderr.puts "usage: estfxbbstohtml infile [outfile]"
    exit
  when 1
    outfile = $stdout
  else
    outfile = open(ARGV[1], 'w')
  end

  open(ARGV[0]) do |file|
    resnum = 1
    while line = file.gets
      line = Kconv.toutf8(line)
      output_header(outfile, get_thread_title(line)) if resnum == 1
      outfile.print(get_formatted_res(resnum, line))
      resnum += 1
    end
    output_footer(outfile)
  end
  outfile.close
end

def output_header(outfile, title)
  outfile.print(<<EOS)
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>#{title}</title>
</head>
<body>
EOS
end

def output_footer(outfile)
  outfile.print("</body></html>\n")
end

def get_thread_title(line)
  if line =~ /^.*<>.*<>.*<>.*<>(.+)$/
    $1
  else
    '(タイトル不明)'
  end
end

def get_formatted_res(resnum, line)
  line.gsub!('<b>', '')
  line.gsub!('</b>', '')
  if line =~ /^(.*)<>(.*)<>(.*)<>(.*)<>.*$/
    handle = $1
    mailaddr = $2
    date = $3
    content = $4
    "<p>#{resnum} 名前:#{handle} [#{mailaddr}] #{date}<br>#{content}</p>\n"
  end
end

main

一応、中身を説明します。

mainメソッド:はじめに呼び出される処理です。引数の数を判別し、0個なら使い方を表示し、2個なら出力ファイルをオープンします。次に入力ファイルから1行ずつ読んだデーターを加工し、出力します。

output_headerメソッド:HTMLのヘッダーを出力します。指定されたタイトルを“”〜“”に入れて出力します。

output_footerメソッド:HTMLのフッターを出力します。

get_thread_titleメソッド:与えられた1つのレス・データーに含まれるスレッドタイトルを返します。スレッドタイトルが取得できなかった場合には「(タイトル不明)」を返します。

get_formatted_resメソッド:与えられた1つのレス・データーを加工し、HTMLの“p”タグで囲まれた段落として返します。

フィルターの出力

上記の「ゲームの話しよう」のスレッド・データーを読み込ませると、次のように出力します。

<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ゲームの話しよう</title>
</head>
<body>
<p>1 名前:よくある名無しさん [sage] 2009/07/08(水) 01:22:33<br>ゲームの話しようぜ!</p>
<p>2 名前:よくある名無しさん [] 2009/07/08(水) 08:17:28<br>しようしよう</p>
<p>3 名前:RPG名無しさん [sage] 2009/07/10(水) 21:45:16<br>ゲームって面白いよね。<br>最近ドラクエやってる。</p>
</body></html>

これで独自フィルターが完成しました。