2008-09-17 14 views
51

¿Cómo hago una diferencia de dos cadenas o matrices en Ruby?diff a ruby ​​string o array

+0

he reformulado esta pregunta con la esperanza de que ahora puede volver a abrirse. Creo que la pregunta era válida, simplemente redactada de una manera que hacía parecer que daría lugar a muchas respuestas de opinión. Si desea ayudar a reabrir esto, debería ver un pequeño enlace de "reabrir" justo debajo de las etiquetas de pregunta "ruby" y "diff". – Gerry

+0

esta es la décima pregunta que he encontrado esta semana que se ha marcado como fuera del tema. no está fuera del tema es una gran pregunta. por favor, monitores de pasillo, dejen de hacer esto. – user1130176

+0

Para cadenas puede utilizar esta respuesta http://stackoverflow.com/a/42573286/745489 – Dzmitry

Respuesta

20
+19

Nota: diff.rb es GPL –

+15

Para aquellos que no asimilan las implicaciones de GPL: incluye un concepto de 'copyleft' que exige que cualquier código propietario en el que lo incorpores te obligue a abrir el código fuente y GPL-regalar tu código previamente propietario. –

+1

enlace (http://users.cybercity.dk/~dsl8950/ruby/diff.html) está muerto –

30

Para matrices, utilice 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, desde foo que también está en sustancia pegajosa, dejando sólo el elemento 1. No sé cómo hacer esto por dos cuerdas, pero hasta que alguien que conozca acerca de los mensajes puede convertir cada cadena en una matriz, usar el operador menos y luego convertir el resultado.

+2

Esto es incorrecto. foo = [1,2,3] bar = [4,5,6] foo - bar # => [1,2,3] aplicación de Ruby es correcta, pero no hacer esto es delgada qué fue lo que preguntó la pregunta. –

+6

Para evitar el punto de Chris L', puede hacer (foo - bar) + (bar - foo). Para obtener todas las diferencias entre las matrices (o cadenas si usa .to_a) – diedthreetimes

18

Para cuerdas, probaría primero la gema Ruby que @ sam-saffron 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 
5

También hay diff-lcs que está disponible como una joya. No se ha actualizado desde 2004, pero lo hemos estado utilizando sin ningún problema.

Editar: Se lanzó una nueva versión en 2011. Parece que está de vuelta en desarrollo activo.

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

+0

Se ha enviado una nueva actualización a rubygems en 2011. –

+0

¿Alguien ha tenido éxito al usar esto para HTML? – aaandre

5

El HTMLDiff que da01 @ menciones anteriormente trabajó 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 complemento acts_as_audited.

+0

Gracias, esto fue extremadamente útil. – aaandre

2

Tuve 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 desde el sistema operativo 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 
+1

el uso de archivos temporales generalmente es una mala idea cuando tiene una opción en memoria disponible. – epochwolf

+0

@epochwolf ¿Cómo estás haciendo diff lectura de memoria? Solo admite archivos de difusión, hasta donde yo sé. – Gerry

21

llegué frustrado con la falta de una buena biblioteca para esto en rubí, así que escribí http://github.com/samg/diffy. Utiliza diff debajo de las cubiertas, y se enfoca en ser conveniente y proporcionar opciones de salida bonitas.

+2

Estoy usando diffy para uno de mis proyectos. Simplemente funciona. Gracias. – ardsrk

2

sólo para el beneficio de las personas de Windows: Diffy se ve brillante, pero me creer que sólo funcionará en * nix (corríjanme si Me equivoco). Ciertamente no funcionó en mi máquina.

Differ funcionó para mí (Windows 7 x64, Ruby 1.8.7).

+0

Ahora hay algo de soporte de Windows horneado. Hay algunos detalles sobre qué tipo de configuración debe hacer en el archivo README. https://github.com/samg/diffy#on-windows – samg

0

Para obtener el caracter en la resolución personaje que añade una nueva función 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"] 

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