まあ、ソースコードはテストコードや変換コードとなんだかんだ長くなってしまいましたし、SkyDriveのZIPに入っているので詳しくは省きますが、ちょっと解説。
今回の日付の展開ロジックは割と力業。文字列を正規表現でチェックして、引っかかれば日付を計算して返すというもの(メインルーチンで書式化する)。
WEEKINDEX = {
"にち" => 0,
"げつ" => 1,
"か" => 2,
"すい" => 3,
"もく" => 4,
"きん" => 5,
"ど" => 6,
"日" => 0,
"月" => 1,
"火" => 2,
"水" => 3,
"木" => 4,
"金" => 5,
"土" => 6
}
INDEXINDEX = {
"いち" => 1,
"に" => 2,
"さん" => 3,
"よん" => 4,
"し" => 4,
"ご" => 5,
"一" => 1,
"二" => 2,
"三" => 3,
"四" => 4,
"五" => 5,
}
def get_date(source_str)
date = Date.today
case source_str
when /さきおととい/, /一昨昨日/
date -= 3
when /おととい/, /一昨日/
date -= 2
when /きのう/, /昨日/
date -= 1
when /きょう/, /今日/
when /やのあさって/, /やなさって/, /弥明後日/
date += 4
when /しあさって/, /明明後日/
date += 3
when /あさって/, /明後日/
date += 2
when /あした/, /明日/
date += 1
when /(\d+|[0-9]+)(にちご|かご|日後)/
date += Regexp.last_match(1).tr('0-9', '0-9').to_i
when /(?:(?:こんど|つぎ|今度|次)の)(にち|げつ|か|すい|もく|きん|ど|日|月|火|水|木|金|土)(?:よう|曜)/
date += (date.wday * -1 + 7) + WEEKINDEX[Regexp.last_match(1)]
when /(?:らいげつ|来月)の(?:だい|第)(\d|[0-9]|いち|に|さん|し|よん|ご|一|二|三|四|五)(にち|げつ|か|すい|もく|きん|ど|日|月|火|水|木|金|土)(?:よう|曜)/
windex = Regexp.last_match(1).tr('0-9', '0-9').to_i
windex = INDEXINDEX[Regexp.last_match(1)] if windex == 0
date = Date.new(date.year, date.month, -1) + 1
index = WEEKINDEX[Regexp.last_match(2)]
res = 7 - date.wday + index + 7 * (windex - 1)
res -= 7 if date.wday <= index
date += res
raise TypeError, "invalid date!" if date.month != Date.today.month + 1
when /(?:せんげつ|先月)の(?:だい|第)(\d|[0-9]|いち|に|さん|し|よん|ご|一|二|三|四|五)(にち|げつ|か|すい|もく|きん|ど|日|月|火|水|木|金|土)(?:よう|曜)/
windex = Regexp.last_match(1).tr('0-9', '0-9').to_i
windex = INDEXINDEX[Regexp.last_match(1)] if windex == 0
date = Date.new(date.year, date.month, 1) - 1
date -= date.day - 1
index = WEEKINDEX[Regexp.last_match(2)]
res = 7 - date.wday + index + 7 * (windex - 1)
res -= 7 if date.wday <= index
date += res
raise TypeError, "invalid date!" if date.month != Date.today.month - 1
else
date = nil
end
return date
end
来月と先月のカレンダーを作る部分は、TCalのソースコードを参考に。Delphiのコードを見たのは久しぶりでした・・・。
あと、気づいた点として、ATOKの変換プラグインを作るとき、引数に入ってくるのは「そのときキャレット部分表示されてる状態の未変換文字列」です。
わかりにくいですが、早い話入力しようとしている文字列のひらがなとも限りませんし、漢字とも限りません*1。まあ今回は、「きょう」といれて「今日」と真っ先に出てこない環境も珍しいので「きょう」と「今日」の二種類だけサポートしましたが、場合によってはそれ以外も必要になるということです。変換方法にバリエーションを持たせるタイプのプラグインを作るのはなかなか難しいかもしれません。
書式化コードは以下のようなかんじ。Dateクラスのstrftimeメソッドを使ってます。
if date.class == Date then
FORMATS.each{ |f|
f.gsub!(/%j/, ABBR_DAYNAMES[date.wday])
f.gsub!(/%J/, DAYNAMES[date.wday])
candidate.push(addhyoki(
date.strftime(f),
"#{PLUGINNAME}:#{source}の日付",
"#{source}の日付の文字列表現です",
"definite_string"
))
}
end
ネットを探すと、strftimeで日本語文字列を曜日に変換できるようにする方法として、「Date::ABBR_DAYTIMES」を置き換えてしまう と言う方法が紹介されていましたが、最新のRubyでは動かないみたいです。残念。 というわけでちょっと不細工ですが、こんな感じになりました。
ATOKの変換プラグインは、結構簡単に作れます。まあ、使えるものを作るにはそれなりの工数が必要ですが、工夫しておもしろいものを作って見るといいんじゃないでしょうか。