ダジャレ判定機作ったよ

ダジャレが好きなのだ。
本来関連のない言葉同士を自由に結びつけ、語感のリズムで羽ばたいてシニフィエの宇宙を再構築する、そんなおやじギャグはとてもいとおしい。
だからぼくはダジャレのスキルを向上すべく日々研鑽しているのだ。
そういつもダジャレのことばかり考えている。PDCAサイクルを回して技術をみがいていく。
いやそれにはダジャレ度が定量的に計測可能でなくてはならない。
そうだ、ダジャレ度を測定するための機械を作ろう。←いまここ
 

そんなわけでダジャレの上手さを評価するウェブサービスを作りました。
もじった言葉ともとの言葉を比較して似ていると評価が高くなります。
ダジャレというより、いわゆるボキャブラですね。
 
ダジャレ判定機 (http://aikelab.net/dajare/)

 
文字列比較の仕組みはこんな感じです。
 ・MeCab形態素解析して漢字を発音通りのよみがなに変換する
 ・大文字小文字などの表記ゆれを統一
 ・Ruby/Romkanでローマ字に変換
 ・レーベンシュタイン距離を計算
いったんローマ字にすることで、母音が一致しているような言葉の評価が高くなります。
 

 
ソース

#!/usr/bin/ruby

$KCODE='UTF8'

require 'jcode'
require 'MeCab'
require "kconv"
require 'romkan'

class Vocabla
  def initialize
    @mecab = MeCab::Tagger.new('-F%pS%f[8] -U%M -E\n')
  end

  def judge(s1, s2)
    rs1 = to_romaji(s1)
    rs2 = to_romaji(s2)
    dist = levenshtein(rs1, rs2)
    len = [utf8_length(rs1), utf8_length(rs2)].max
    score = 100 - (dist * 100 / len) 
  end

  def level(score)
    case score
      when 0..29
      "意味不明ダジャレ"
      when 30..64
      "難解ダジャレ"
      when 65..79
      "おやじギャグ"
      when 80..89
      "秀逸ダジャレ"
      when 90..94
      "絶妙ダジャレ"
      when 95..99
      "超絶ダジャレ"
      when 100
      "完全に一致"
      end
  end

  def to_romaji(s)
    s ||= ""
    ss = @mecab.parse(s)          # 漢字->カタカナ変換
    ss.tr!('a-zA-Z','a-zA-Z') # 英数文字を半角に変換
    ss.downcase!                  # 英数文字を小文字に変換
    ss.tr!('ァ-ン','ぁ-ん')       # カタカナ->ひらがな変換
    ss.gsub!('','')           # 'を'->'お'変換
    ss.gsub!(/[  ]/,'')          # 空白文字の削除
    ss.gsub!(/[・!、。]/,'')     # 記号文字の削除
    ss = ss.to_roma.to_kunrei     # ローマ字(訓令式)変換
    return ss
  end

  # levenshtein function for utf8 multibyte character (ruby 1.8)
  # based on
  #   http://subtech.g.hatena.ne.jp/cho45/20091008/1254934083
  def levenshtein(a, b)
    a_length = utf8_length(a)
    b_length = utf8_length(b)
    case
    when a.empty?
      b_length
    when b.empty?
      a_length
    else
      d = Array.new(a_length + 1) { |s|
        Array.new(b_length + 1, 0)
      }
      
      (0..a_length).each do |i|
        d[i][0] = i
      end
      
      (0..b_length).each do |j|
        d[0][j] = j
      end

      (1..a_length).each do |i|
        (1..b_length).each do |j|
          cost = (utf8_substring(a, i - 1) == utf8_substring(b, j - 1)) ? 0 : 1
          d[i][j] = [
                     d[i-1][j  ] + 1,
                     d[i  ][j-1] + 1,
                     d[i-1][j-1] + cost
                    ].min
        end
      end

      d[a_length][b_length]
    end
  end

  def utf8_length(s)
    s.split(//u).length
  end

  def utf8_substring(s, n)
    s.split(//u)[n]
  end

end

 

 
ウェブインタフェースはSinatraで書いたらチョー簡単。さよならcgi.rb。いままでありがとう。