ナイツ関数(ボケの方)
Posted feedbacks - Ruby
JavaとSmalltalkの投稿を参考に書いてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #! /usr/bin/ruby -Ks
class LevenshteinDistance
def self.distance(a, b)
table = Array.new(a.split('').size + 1) do |i|
i == 0 ? (0..b.split('').size).to_a : Array.new(b.split('').size).unshift(i)
end
(1..table.size - 1).each do |i|
(1..table[i].size - 1).each do |j|
table[i][j] = [
table[i - 1][j] + 1,
table[i][j - 1],
table[i - 1][j - 1] + (a.split('')[i - 1] == b.split('')[j - 1] ? 0 : 1)
].min
end
end
table.last.last
end
end
class Knights
attr_accessor :dictionary
def initialize(dict_file)
self.dictionary = []
File.open(dict_file) { |f| f.each { |line| self.dictionary.concat(line.split(/\s+/)) } }
self
end
def translate(source)
source.split(/\s+/).map do |w|
list = self.dictionary.select { |d| yield(w, d) }.unshift(w)
list[rand(list.size)]
end
end
end
source = <<EOS
ドウカク org ヘ ヨウコソ
コノ サイト ハ ダサレタ オダイ ヲ イカニ トクカ キソイアウ
プログラマ ノ タメノ コロシアム デス
トウコウ ヲ タメシテ ミタイ カタ ハ テスト
トリアエズ ナガメテ ミタイ カタ ハ ゲンゴ ノ イチラン ガ オススメ デス
EOS
knights = Knights.new("./path/to/word_list.txt")
puts "入力:\n#{source}"
puts "出力:"
source.each_line do |line|
puts(
knights.translate(line) do |w, d|
LevenshteinDistance.distance(w, d).to_f / [w.split('').size, d.split('').size].sort.first < 0.4
end.join(" ")
)
end
puts "出力:"
source.each_line do |line|
puts(
knights.translate(line) do |w, d|
(w.split('').size - d.split('').size).abs <= 1 && w.split('').first == d.split('').first && w.split('').last == d.split('').last
end.join(" ")
)
end
|
レーベンシュタイン距離の計算処理に間違いがあったので修正したものを。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #! /usr/bin/ruby -Ks
class LevenshteinDistance
def self.distance(a, b)
table = Array.new(a.split('').size + 1) do |i|
i == 0 ? (0..b.split('').size).to_a : Array.new(b.split('').size).unshift(i)
end
(1..table.size - 1).each do |i|
(1..table[i].size - 1).each do |j|
table[i][j] = [
table[i - 1][j] + 1,
table[i][j - 1] + 1,
table[i - 1][j - 1] + (a.split('')[i - 1] == b.split('')[j - 1] ? 0 : 1)
].min
end
end
table.last.last
end
end
class Knights
attr_accessor :dictionary
def initialize(dict_file)
self.dictionary = []
File.open(dict_file) { |f| f.each { |line| self.dictionary.concat(line.split(/\s+/)) } }
self
end
def translate(source)
source.split(/\s+/).map do |w|
(list = self.dictionary.select { |d| yield(w, d) }).empty? ? w : list[rand(list.size)]
end
end
end
source = <<EOS
ドウカク org ヘ ヨウコソ
コノ サイト ハ ダサレタ オダイ ヲ イカニ トクカ キソイアウ
プログラマ ノ タメノ コロシアム デス
トウコウ ヲ タメシテ ミタイ カタ ハ テスト
トリアエズ ナガメテ ミタイ カタ ハ ゲンゴ ノ イチラン ガ オススメ デス
EOS
puts "入力:\n#{source}"
puts "出力:"
knights = Knights.new("/path/to/wordlist.txt")
source.each_line do |line|
puts(
knights.translate(line) do |w, d|
LevenshteinDistance.distance(w, d).to_f / [w.split('').size, d.split('').size].max < 0.5
end.join(" ")
)
end
puts "出力:"
source.each_line do |line|
puts(
knights.translate(line) do |w, d|
(w.split('').size - d.split('').size).abs <= 1 && w.split('').first == d.split('').first && w.split('').last == d.split('').last
end.join(" ")
)
end
|
なるべく面白くボケる様に調整してみましたが、その所為でマジックナンバー溢れるヘンなコードになってしまいました。 あと一々単語データ全部について編集距離を計算してるので、Ruby1.8.x系だと遅くてお話になりません。なんともはや……。 -- ドウヤク org ヘ ヨワミソ コノ サイト ハ ダサレタ オダイ ヲ イチニン トクカ キソイアウ プログラマ ノ タメノ コロシヤ デス トウコウ ヲ タメシテ ミタイ カタ ハ テスト トリアエズ ナガソデ ミタマヤ カタ ハ ゲンタツ ノ イモバン ガ オツトメ デス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | if RUBY_VERSION >= "1.9"
class Array
def choice
self[ rand(self.size) ]
end
end
end
def levenstein(a, b)
ld = Array.new(a.size+1){ Array.new(b.size+1){0} }
0.upto(a.size){|i|
ld[i][0] = i
}
0.upto(b.size){|i|
ld[0][i] = i
}
1.upto(a.size){|i|
1.upto(b.size){|j|
t = a[i-1] == b[i-1] ? 0 : 1
ld[i][j] = [ld[i-1][j]+1, ld[i][j-1]+1, ld[i-1][j-1] + t].min
}
}
return ld[-1][-1]
end
DIC = File.read("words.dat").encode("UTF-8").split(/\s+/m)
def knights(text)
text.each_line.map{|ln|
ln.split(" ").map{|wd|
DIC.find_all{|w2| levenstein(wd, w2)*15/(wd.size+w2.size) < rand(6) && wd[0] == w2[0]}.choice || wd
}.join(" ")
}.join($/)
end
if $0 == __FILE__
puts knights($<.read)
end
|




syat
#8549()
[
Other
]
Rating-2/2=-1.00
(ナベアツ算を見てて思いつきました)
入出力の方法は標準入出力や引数・戻り値など、扱いやすい方法でかまいません。
文字単位でランダムに間違えても面白くないので、単語のリストから似た単語の候補を探すようにしてください。英単語でもOKです。単語のリストは参考ページからダウンロードしたものを加工して利用すると良いと思います。(4000個あります)
結果がつまらなくても構いませんが、面白いボケをうむ工夫があると良いです。
※人が考えたボケは求めてませんよ!
入力の例として「どう書く?org」の前文をお借りしました。ご自分でヤホーで調べたりして手ごろな文章を見つけて下しあ。
see: 日本語単語リスト
Rating-2/2=-1.00-0+
[ reply ]