オーバーロードWEB版のルビを青空文庫形式に
オーバーロードWEB版のテキスト中のルビを、青空文庫形式の《》に変換します。魔法名は区切りが分かりやすいのですが、他の固有名詞は区切りが明確ではないため、MeCabによる形態素解析を用いてある程度単語の区切りを推測し、最終的に人間が区切りを判断するハイブリッド型になっています。
文章中ルビとしてあらわれるのは <> <> 〈〉 ですが、ごくわずかに()が使われているので、手動での置換が必要です(前編で2箇所程度)
使用言語Ruby(1.9以上必須)
# -*- Encoding: Windows-31J -*- # # Copyright 2012 whiteleaf. All rights reserved. # # オーバーロードの 固有名詞<読み方> を |固有名詞《読み方》に変換する require_relative "mecab" =begin 訂正画面イメージ ┌─────────────────────────────────┐ │...シャルティアの|妾である吸血鬼の花嫁《ヴァンパイア・ブライド》 │ │ ^ │ │ルビ開始位置の確認 (Yes/Skip/Forward/Backward):ffff │ └─────────────────────────────────┘ ↓ ┌─────────────────────────────────┐ │...シャルティアの妾である|吸血鬼の花嫁《ヴァンパイア・ブライド》 │ │ ^ │ │ルビ開始位置の確認 (Yes/Skip/Forward/Backward):y │ └─────────────────────────────────┘ =end def make_text(prev_text, name, ruby) "#{prev_text}|#{name}《#{ruby}》" end def output_input_message print "ルビ開始位置の確認 (Yes/Skip/Forward*/Backward*): " end def output_interface(prev_text, name, ruby) is_omit = prev_text.length > 7 omit_text = (is_omit ? "‥‥" : "") + prev_text[(is_omit ? -7 : 0)..-1] puts make_text(omit_text, name, ruby) puts " " * omit_text.length + "^" output_input_message end def wait_user_input(prev_text, name, ruby) output_interface(prev_text, name, ruby) while input = STDIN.gets case input[0].downcase when "y" return make_text(prev_text, name, ruby) when "s" return nil when "f" count = input.match(/(f+)/i)[1].length prev_text += name[0...count] _name = name[count..-1] name = (_name ? _name : "") output_interface(prev_text, name, ruby) when "b" count = input.match(/(b+)/i)[1].length _prev_text = prev_text[-count..-1] name = (_prev_text ? _prev_text : prev_text) + name prev_text = (_prev_text ? prev_text[0...-count] : "") output_interface(prev_text, name, ruby) else output_input_message end end end Mecab = MecabLib::Mecab.new("") def extract_ruby(line) line.gsub(/(.+?)[<<〈](.+?)[>>〉]/) do match_name_message = $1 match_ruby = $2 match_all = $& node = Mecab.sparse_tonode(match_name_message.force_encoding(Encoding::Shift_JIS)) nodes = [] while node.hasNext node = node.next break if node.surface == "EOS" nodes << { surface: node.surface.force_encoding(Encoding::Windows_31J), pos: node.pos.force_encoding(Encoding::Windows_31J), root: node.root.force_encoding(Encoding::Windows_31J), reading: node.reading.force_encoding(Encoding::Windows_31J), pronunciation: node.pronunciation.force_encoding(Encoding::Windows_31J) } end name = "" prev_text = "" is_before_word_alphabet = false detected = false _debug_before_sujou = "" nodes.reverse.each do |node| unless detected sujou = node[:pos].split(",") if ["接頭詞", "名詞", "助詞", "助動詞", "形容詞"].include?(sujou[0]) if (sujou[0] == "助詞" && sujou[1] != "連体化") || (sujou[0] == "助動詞" && sujou[5] != "体言接続") detected = true else if node[:surface] =~ /^[a-zA-Z]+$/ if is_before_word_alphabet name = " " + name end is_before_word_alphabet = true else is_before_word_alphabet = false end name = node[:surface] + name next end else detected = true end end prev_text = node[:surface] + prev_text end result = wait_user_input(prev_text, name, match_ruby) result ? result : match_all end end if ARGV.count == 0 puts "ファイル名を指定して下さい" exit end ARGV.each do |fname| puts "#{fname} の処理を開始します" puts "-" * 70 open(fname) do |read_fp| open("[OLルビ変換]#{fname}", "w") do |write_fp| read_fp.each do |line| result = extract_ruby(line) write_fp.puts(result) end end end puts "-" * 30 puts "#{fname} の変換が完了しました。" end Mecab.destroy