Frage
Wie mache ich ein diff von zwei Strings oder Arrays in Ruby?
Lösung
diff.rb ist, was Sie wollen, die in verfügbar http : //users.cybercity.dk/~dsl8950/ruby/diff.html über das Internet-Archiv:
http://web.archive.org/web/20140421214841/http://users.cybercity.dk:80/~dsl8950/ruby/diff.html
Andere Tipps
Für Arrays, verwenden Sie den Minus-Operator. Zum Beispiel:
>> foo = [1, 2, 3]
=> [1, 2, 3]
>> goo = [2, 3, 4]
=> [2, 3, 4]
>> foo - goo
=> [1]
Hier ist die letzte Zeile entfernt alles von foo, die auch in Goo ist, so dass nur das Element 1. Ich weiß nicht, wie dies für zwei Strings zu tun, aber bis jemand, der Beiträge über sie weiß, könnte man einfach jede konvertieren String in ein Array, verwenden Sie den minus-Operator, und dann das Ergebnis zurück zu konvertieren.
habe ich mit dem Fehlen einer guten Bibliothek für diese in Ruby frustriert, also schrieb ich http: // GitHub. com / SAMG / Diffy . Es verwendet diff
unter der Decke, und konzentriert sich auf seinem bequem und ziemlich Ausgabeoptionen.
Für Strings, würde ich zuerst das Ruby-Gem versuchen, dass @ sam-Safran unten erwähnt. Es ist einfacher zu installieren: http://github.com/pvande/differ/tree/master
gem install differ
irb
require 'differ'
one = "one two three"
two = "one two 3"
Differ.format = :color
puts Differ.diff_by_word(one, two).to_s
Differ.format = :html
puts Differ.diff_by_word(one, two).to_s
Die HTMLDiff dass @ DA01 Nennungen oben für mich gearbeitet.
script/plugin install git://github.com/myobie/htmldiff.git
# bottom of environment.rb
require 'htmldiff'
# in model
class Page < ActiveRecord::Base
extend HTMLDiff
end
# in view
<h1>Revisions for <%= @page.name %></h1>
<ul>
<% @page.revisions.each do |revision| %>
<li>
<b>Revised <%= distance_of_time_in_words_to_now revision.created_at %> ago</b><BR>
<%= Page.diff(
revision.changes['description'][0],
revision.changes['description'][1]
) %>
<BR><BR>
</li>
<% end %>
# in style.css
ins.diffmod, ins.diffins { background: #d4fdd5; text-decoration: none; }
del.diffmod, del.diffdel { color: #ff9999; }
Sieht ziemlich gut. Durch die Art und Weise habe ich dies mit dem acts_as_audited
Plugin.
Es gibt auch diff-lcs
, die als Juwel zur Verfügung steht. Es hat sich seit 2004 nicht aktualisiert worden, aber haben wir es ohne Probleme im Einsatz.
Edit:. Eine neue Version im Jahr 2011 veröffentlicht wurde Sieht aus wie es wieder in der aktiven Entwicklung ist
t=s2.chars; s1.chars.map{|c| c == t.shift ? c : '^'}.join
Diese einfache Linie gibt einen ^
in den Positionen, die nicht übereinstimmen. Das ist oft genug und es ist copy / paste-fähig.
Ich habe gerade ein neues Projekt, das sehr flexibel scheint:
http://github.com/pvande/differ/tree/master
Der Versuch, es aus und versuchen, irgendeine Art von Bericht zu veröffentlichen.
Ich hatte den gleichen Zweifel und die Lösung fand ich nicht 100% Rubin, aber ist das Beste für mich. Das Problem mit diff.rb ist, dass es kein schönes Formatierer haben, die Diffs in einem humanisierten Weg zu zeigen. So habe ich diff von dem O mit diesem Code:
def diff str1, str2
system "diff #{file_for str1} #{file_for str2}"
end
private
def file_for text
exp = Tempfile.new("bk", "/tmp").open
exp.write(text)
exp.close
exp.path
end
Just zum Nutzen von Windows Menschen: Diffy sieht brillant, aber ich glaube es wird nur auf * nix arbeiten (korrigiert mich wenn ich falsch liege). Sicherlich hat es nicht auf meinem Rechner arbeiten.
ein Vergnügen für mich Differ gearbeitet (Windows 7 x64 Ruby 1.8.7).
Vielleicht Array.diff über Affen-Patch hilft ...
http://grosser.it / 2011/07/07 / Rubin-Array-diffother-Unterschied-zwischen-2-Arrays /
Um zeichenweise Auflösung zu erhalten habe ich eine neue Funktion Damerau-levenshtein gem
require "damerau-levenshtein"
differ = DamerauLevenshtein::Differ.new
differ.run "Something", "Smothing"
# returns ["S<ins>o</ins>m<subst>e</subst>thing",
# "S<del>o</del>m<subst>o</subst>thing"]
oder mit Analyse:
require "damerau-levenshtein"
require "nokogiri"
differ = DamerauLevenshtein::Differ.new
res = differ.run("Something", "Smothing!")
nodes = Nokogiri::XML("<root>#{res.first}</root>")
markup = nodes.root.children.map do |n|
case n.name
when "text"
n.text
when "del"
"~~#{n.children.first.text}~~"
when "ins"
"*#{n.children.first.text}*"
when "subst"
"**#{n.children.first.text}**"
end
end.join("")
puts markup