Skip to content

Instantly share code, notes, and snippets.

@ignasio
Created July 26, 2016 18:29
Show Gist options
  • Save ignasio/bcb7c4f7d14a9afd0e3438af77ede179 to your computer and use it in GitHub Desktop.
Save ignasio/bcb7c4f7d14a9afd0e3438af77ede179 to your computer and use it in GitHub Desktop.
diff between two files based on lcs
class Diff
def initialize(_old,_new)
@old = _old
@new = _new
end
def results
@global_index = {}
@old.each_with_index{|v,i| @global_index[v] = i}
@new.each_with_index{|v,i| @global_index[v] = i}
result = diff(@old, @new).group_by(&:first).map{|k, v| {k => v.map(&:last).flatten}}.reduce Hash.new, :merge
both = @old | @new
ignore = []
delta = 0
both.each_with_index do |val, i|
if ignore.include? val
delta = delta + 1
next
end
variant = result.select{|k,v| v.include?(val)}
show_both = variant.values.flatten.map{|v| @global_index[v]}.uniq.count == 1
p "#{i+1-delta} #{variant.keys.first} #{show_both ? variant.values.flatten.map(&:strip).join('|') : val.strip} "
if show_both
variant.values.flatten.each do |x|
ignore.push x
end
end
end
result
end
def diff(_old, _new)
_old ||= []
_new ||= []
old_index = {}
_old.each_with_index do |val, i|
(old_index[val] ||= []).push(i)
end
conjunction = {}
start_old = 0
start_new = 0
length = 0
_new.each_with_index do |val,i|
_conjunction = {}
Array(old_index[val]).each do |j|
_conjunction[j] = (conjunction[j-1] || 0) + 1
if (_conjunction[j] > length)
length = _conjunction[j]
start_old = j - length + 1
start_new = i - length + 1
end
end
conjunction = _conjunction
end
if length == 0
modified = []
_old.each{|i| _new.each{|j| modified.push(_old.delete(i),_new.delete(j)) if @global_index[i]==@global_index[j] }}
return [[_old.empty? ? [] : ['-',_old]],[_new.empty? ? [] : ['+',_new]], [['*',modified]]].flatten(1).reject { |c| c.empty? }
else
return diff(_old[0,start_old],_new[0,start_new]) + [['=',_new[start_new, start_new + length -1]]] + diff(_old[start_old+length .. -1],_new[start_new+length..-1])
end
end
end
@file1 = File.readlines "file1.txt"
@file2 = File.readlines "file2.txt"
Diff.new(@file1,@file2).results
Some
Simple
Text
File
Another
Text
File
With
Additional
Lines
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment