index - diff a ruby string o array
ruby slice (11)
Acabo de encontrar un nuevo proyecto que parece bastante flexible:
http://github.com/pvande/differ/tree/master
Pruébalo e intentará publicar algún tipo de informe.
¿Cómo hago una diferencia de dos cadenas o matrices en Ruby?
El HTMLDiff que menciona @ da01 arriba funcionó para mí.
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; }
Se ve bastante bien. Por cierto, utilicé esto con el plugin acts_as_audited
.
Me frustré la falta de una buena biblioteca para esto en ruby, así que escribí http://github.com/samg/diffy . Utiliza diff
bajo las cubiertas, y se enfoca en ser conveniente y en proporcionar bonitas opciones de salida.
Para arreglos, use el operador menos. Por ejemplo:
>> foo = [1, 2, 3]
=> [1, 2, 3]
>> goo = [2, 3, 4]
=> [2, 3, 4]
>> foo - goo
=> [1]
Aquí la última línea elimina todo de foo que también está en goo, dejando solo el elemento 1. No sé cómo hacer esto para dos cadenas, pero hasta que alguien que sepa publicar sobre eso, podrías simplemente convertir cada cadena a una array, use el operador menos y luego convierta el resultado.
Para cuerdas, primero probaría la gema Ruby que @ sam-azafrán menciona a continuación. Es más fácil de instalar: 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
Para obtener la resolución personaje por personaje, agregué una nueva función a la gema damerau-levenshtein
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"]
o con el análisis:
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
Quizás Array.diff a través de monkey-patch ayuda ...
http://grosser.it/2011/07/07/ruby-array-diffother-difference-between-2-arrays/
Solo para el beneficio de la gente de Windows: diffy se ve genial, pero creo que solo funcionará en * nix (corrígeme si me equivoco). Ciertamente no funcionó en mi máquina.
Differ funcionó para mí (Windows 7 x64, Ruby 1.8.7).
También hay diff-lcs
que está disponible como una gema. No se ha actualizado desde 2004, pero lo hemos estado usando sin ningún problema.
Editar: Se lanzó una nueva versión en 2011. Parece que está de vuelta en desarrollo activo.
Tenía la misma duda y la solución que encontré no es 100% rubí, pero es lo mejor para mí. El problema con diff.rb es que no tiene un formateador bonito, para mostrar los difs de una manera humanizada. Así que utilicé diff del SO con este código:
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
diff.rb es lo que quieres, que está disponible en http://users.cybercity.dk/~dsl8950/ruby/diff.html a través del archivo de internet:
http://web.archive.org/web/20140421214841/http://users.cybercity.dk:80/~dsl8950/ruby/diff.html