it-swarm-vi.tech

diff a Ruby chuỗi hoặc mảng

Làm cách nào để thực hiện một khác biệt của hai chuỗi hoặc mảng trong Ruby?

54
Josh Moore
20
Brian Mitchell

Đối với mảng, sử dụng toán tử trừ. Ví dụ:

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

Ở đây, dòng cuối cùng loại bỏ mọi thứ khỏi foo cũng trong goo, chỉ để lại phần tử 1. Tôi không biết làm thế nào cho hai chuỗi, nhưng cho đến khi ai đó biết bài đăng về nó, bạn có thể chuyển đổi từng chuỗi thành một chuỗi mảng, sử dụng toán tử trừ, và sau đó chuyển đổi kết quả trở lại.

32
Chris Bunch

Tôi đã thất vọng với việc thiếu một thư viện tốt cho điều này trong Ruby, vì vậy tôi đã viết http://github.com/samg/diffy . Nó sử dụng diff dưới vỏ bọc, và tập trung vào việc thuận tiện và cung cấp các tùy chọn đầu ra đẹp.

24
samg

Đối với chuỗi, trước tiên tôi sẽ dùng thử Ruby Đá quý mà @ sam-saffron được đề cập bên dưới. Dễ cài đặt hơn: http://github.com/pvande/differ/tree/chủ

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

HTMLDiff mà @ da01 đề cập ở trên đã làm việc cho tôi.

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

Trông khá tốt. Bằng cách này, tôi đã sử dụng điều này với acts_as_audited cắm vào.

5
Brian Armstrong

Ngoài ra còn có diff-lcs có sẵn như một viên đá quý. Nó chưa được cập nhật từ năm 2004 nhưng chúng tôi đã được sử dụng nó mà không có bất kỳ vấn đề.

Chỉnh sửa: Một phiên bản mới đã được phát hành vào năm 2011. Có vẻ như nó đã trở lại trong quá trình phát triển tích cực.

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

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

Dòng đơn giản này cung cấp một ^ ở những vị trí không khớp. Điều đó thường đủ và nó có thể sao chép/dán.

3
Steve

Chỉ vì lợi ích của người Windows: diffy trông rất tuyệt nhưng tôi tin rằng nó sẽ chỉ hoạt động trên * nix (sửa tôi nếu tôi sai). Chắc chắn nó không hoạt động trên máy của tôi.

Sự khác biệt đã giúp tôi điều trị (Windows 7 x64, Ruby 1.8.7).

2
russthegibbon

Tôi vừa tìm thấy một dự án mới có vẻ khá linh hoạt:

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

Dùng thử và sẽ cố gắng đăng một số loại báo cáo.

2
Sam Saffron

Tôi đã có cùng nghi ngờ và giải pháp tôi tìm thấy không phải là 100% Ruby, nhưng là giải pháp tốt nhất cho tôi. Vấn đề với diff.rb là nó không có một định dạng đẹp, để hiển thị các khác biệt theo cách nhân hóa. Vì vậy, tôi đã sử dụng diff từ HĐH với mã này:

 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

Để có được ký tự theo độ phân giải ký tự, tôi đã thêm một hàm mới vào đá quý 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"]

hoặc với phân tích cú pháp:

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