سؤال
كيف أقوم بعمل فرق بين سلسلتين أو صفائف في روبي؟
المحلول
diff.rb هو ما تريد، وهو متاح في http://users.cybercity.dk/~dsl8950/ruby/diff.html عبر أرشيف الإنترنت:
http://web.archive.org/web/20140421214841/http://users.cybercity.dk:80/~dsl8950/ruby/diff.html
نصائح أخرى
بالنسبة للمصفوفات، استخدم عامل التشغيل ناقص.على سبيل المثال:
>> foo = [1, 2, 3]
=> [1, 2, 3]
>> goo = [2, 3, 4]
=> [2, 3, 4]
>> foo - goo
=> [1]
هنا يزيل السطر الأخير كل شيء من foo الموجود أيضًا في goo، ويترك العنصر 1 فقط.لا أعرف كيفية القيام بذلك لسلسلتين، ولكن حتى يتمكن شخص يعرف المنشورات حول هذا الموضوع، يمكنك فقط تحويل كل سلسلة إلى مصفوفة، واستخدام عامل التشغيل ناقص، ثم تحويل النتيجة مرة أخرى.
لقد شعرت بالإحباط بسبب عدم وجود مكتبة جيدة لهذا في روبي، لذلك كتبت http://github.com/samg/diffy.يستخدم diff
تحت الأغطية، ويركز على أن يكون ملائمًا، ويوفر خيارات إخراج جميلة.
بالنسبة للسلاسل، سأحاول أولاً تجربة جوهرة الياقوت التي ذكرها @sam-saffron أدناه.إنه أسهل في التثبيت: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
لقد نجح HTMLDiff الذي ذكره @da01 أعلاه بالنسبة لي.
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; }
تبدو جيدة.بالمناسبة لقد استخدمت هذا مع acts_as_audited
توصيل في.
يوجد ايضا diff-lcs
والذي يتوفر كجوهرة. لم يتم تحديثه منذ عام 2004 ولكن لقد تم استخدامه دون أي مشكلة.
يحرر: تم إصدار نسخة جديدة في عام 2011.يبدو أنه عاد إلى التطوير النشط.
t=s2.chars; s1.chars.map{|c| c == t.shift ? c : '^'}.join
هذا الخط البسيط يعطي ^
في المواقف التي لا تتطابق.وهذا غالبًا ما يكفي وهو قابل للنسخ/اللصق.
لقد وجدت للتو مشروعًا جديدًا يبدو مرنًا جدًا:
http://github.com/pvande/differ/tree/master
جربه وسيحاول نشر نوع من التقرير.
كان لدي نفس الشك والحل الذي وجدته ليس روبيًا بنسبة 100٪، ولكنه الأفضل بالنسبة لي.المشكلة في diff.rb هي أنه لا يحتوي على منسق جميل لإظهار الاختلافات بطريقة إنسانية.لذلك استخدمت فرقًا من نظام التشغيل بهذا الرمز:
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
فقط لصالح مستخدمي Windows:يبدو diffy رائعًا ولكني أعتقد أنه لن يعمل إلا على * nix (صححني إذا كنت مخطئًا).بالتأكيد لم يعمل على جهازي.
كان الاختلاف بمثابة متعة بالنسبة لي (Windows 7 x64، Ruby 1.8.7).
ربما يساعد Array.diff عبر Monkey-patch ...
http://grosser.it/2011/07/07/ruby-array-diffother-difference-between-2-arrays/
للحصول على دقة الأحرف حسب الأحرف أضفت وظيفة جديدة إليها جوهرة داميراو-ليفنشتاين
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"]
أو مع التحليل:
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