it-swarm-pt.tech

diff a Ruby string ou matriz

Como faço para diferenciar duas strings ou matrizes no Ruby?

54
Josh Moore
20
Brian Mitchell

Para matrizes, use o operador menos. Por exemplo:

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

Aqui, a última linha remove tudo de foo que também está em goo, deixando apenas o elemento 1. Não sei como fazer isso por duas strings, mas até alguém que saiba postar sobre isso, você pode converter cada string em um matriz, use o operador menos e converta o resultado novamente.

32
Chris Bunch

Fiquei frustrado com a falta de uma boa biblioteca para isso em Ruby, então escrevi http://github.com/samg/diffy . Ele usa diff debaixo das cobertas, e se concentra em ser conveniente e fornecer opções de saída bonitas.

24
samg

Para strings, primeiro testaria a gema Ruby que a sam-saffron mencionou abaixo. É mais 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
19
da01

O HTMLDiff mencionado em @ da01 acima funcionou para mim.

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

Parece muito bom. A propósito, eu usei isso com o acts_as_audited plugar.

5
Brian Armstrong

Há também diff-lcs que está disponível como uma jóia. Não é atualizado desde 2004, mas temos usado sem nenhum problema.

Edit: Uma nova versão foi lançada em 2011. Parece que está de volta ao desenvolvimento ativo.

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

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

Esta linha simples fornece um ^ nas posições que não correspondem. Isso é suficiente e é capaz de copiar/colar.

3
Steve

Apenas para o benefício do pessoal do Windows: diffy parece brilhante, mas acredito que funcionará apenas no * nix (me corrija se estiver errado). Certamente não funcionou na minha máquina.

Differ funcionou para mim (Windows 7 x64, Ruby 1.8.7)).

2
russthegibbon

Acabei de encontrar um novo projeto que parece bastante flexível:

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

Experimente e tentará postar algum tipo de relatório.

2
Sam Saffron

Eu tinha a mesma dúvida e a solução que encontrei não é 100% Ruby, mas é a melhor para mim. O problema com o diff.rb é que ele não possui um formatador bonito, para mostrar os diffs de uma maneira humanizada. Então, eu usei diff do sistema operacional com 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
2
Daniel Cukier

Para obter caractere por resolução de personagem, adicionei uma nova função a 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"]

ou com a análise:

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
1
dimus
1
grosser