Question

Comment puis-je créer un diff de deux chaînes ou tableaux en Ruby?

Était-ce utile?

Autres conseils

Pour les tableaux, utilisez l'opérateur moins. Par exemple:

>> foo = [1, 2, 3]
=> [1, 2, 3]
>> goo = [2, 3, 4]
=> [2, 3, 4]
>> foo - goo
=> [1]

Ici, la dernière ligne supprime tout de foo qui est également dans goo, ne laissant que l'élément 1. Je ne sais pas comment faire cela pour deux chaînes, mais jusqu'à ce que quelqu'un qui connaisse les posts à ce sujet puisse convertir chacun chaîne en un tableau, utilisez l'opérateur moins, puis convertissez le résultat en retour.

Je me suis frustré de l’absence d’une bonne bibliothèque pour cela en ruby, j’ai donc écrit http: // github. com / samg / diffy . Il utilise diff sous les couvertures et cherche avant tout à être pratique et à fournir de jolies options de sortie.

Pour les chaînes, je voudrais d’abord essayer le Ruby Gem @ sam-saffron mentionné ci-dessous. C'est plus facile à installer: 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

Le HTMLDiff mentionné par @ da01 ci-dessus a fonctionné pour moi.

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; }

Ça a l'air bien. A propos, j’ai utilisé cela avec le plugin acts_as_audited .

Il existe également diff-lcs disponible sous forme de gemme. Il n'a pas été mis à jour depuis 2004 mais nous l'utilisons sans problème.

Modifier: Une nouvelle version a été publiée en 2011. On dirait qu'elle est de retour dans le développement actif.

http://rubygems.org/gems/diff-lcs

t=s2.chars; s1.chars.map{|c| c == t.shift ? c : '^'}.join

Cette simple ligne donne un ^ dans les positions qui ne correspondent pas. C'est assez souvent et c'est copiable / collable.

Je viens de trouver un nouveau projet qui semble assez flexible:

http://github.com/pvande/differ/tree/master

Essayez-le et essayerez de poster une sorte de rapport.

J'avais le même doute et la solution que j'ai trouvée n'est pas le rubis à 100%, mais le meilleur pour moi. Le problème avec diff.rb est qu’il n’a pas un joli formateur, pour montrer les diffs de façon humanisée. J'ai donc utilisé diff du système d'exploitation avec ce 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

Juste pour le bénéfice des utilisateurs de Windows: diffy a l’air brillant, mais je crois que cela ne fonctionnera que sur * nix (corrigez-moi si je me trompe). Cela n'a certainement pas fonctionné sur ma machine.

Differ a fonctionné à merveille pour moi (Windows 7 x64, Ruby 1.8.7).

Pour obtenir une résolution caractère par caractère, j'ai ajouté une nouvelle fonction à la gem 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"]

ou avec 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top