-
Notifications
You must be signed in to change notification settings - Fork 0
/
levenshtein_matrix.rb
103 lines (77 loc) · 2.14 KB
/
levenshtein_matrix.rb
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# $ levenshtein far foo
require 'artii'
require 'terminal-table'
module Levenshtein
def self.distance(str1, str2, options = {})
each_step = options[:each_step]
matrix = []
matrix[0] = (0..str1.length).to_a
0.upto(str2.length).each do |i|
matrix[i] ||= []
matrix[i][0] = i
end
str2.each_char.each_with_index do |char1,i|
str1.each_char.each_with_index do |char2, j|
if char1 == char2
puts [:skip, matrix[i][j]].inspect
matrix[i + 1 ][j + 1 ] = matrix[i][j]
else
actions = {
deletion: matrix[i][j + 1] + 1,
insert: matrix[i + 1][j] + 1,
substitution: matrix[i][j] + 1
}
action = actions.sort {|(k,v), (k2, v2)| v <=> v2 }.first
puts action.inspect
matrix[i + 1 ][j + 1 ] = action.last
end
each_step.call(matrix) if each_step
end
end
return matrix[str2.length][str1.length]
end
end
raise "Must provide two arguments" unless ARGV.size >= 2
target = ARGV.shift
provided = ARGV.shift
require "curses"
class LevenDisplay
include Curses
def initialize(target, provided)
@target = [nil] + target.upcase.each_char.map(&:to_s)
@provided = provided.upcase.each_char.map(&:to_s)
@artii = Artii::Base.new font: 'colossal'
end
def clear
end
def asciify(txt)
@artii.asciify(txt.to_s)
end
def matrix(matrix)
provided = [nil] + @provided.dup
table = Terminal::Table.new do |t|
matrix.each_with_index do |row, i|
if matrix.size - 1 == i
# last iteration
last_char = matrix[i].last
t << ([provided.shift] + matrix[i])
else
t << ([provided.shift] + matrix[i])
t << :separator
end
end
end
table.headings = [nil] + @target
table.align_column(0, :left)
puts table
end
end
display = LevenDisplay.new(target, provided)
each_step = Proc.new do |m|
display.clear
display.matrix(m)
puts ""
gets
end
cost = Levenshtein.distance(target, provided, each_step: each_step)
puts display.asciify("Final Cost: #{cost}")