2011-04-16 4 views
5

पर एक diff-पैच को लागू करना ऑफ़लाइन सक्षम स्मार्टफ़ोन ऐप के लिए, मैं एक्सएमएल फ़ाइलों के लिए एक तरफा पाठ सिंक बना रहा हूं। मैं चाहता हूं कि मेरा सर्वर लक्ष्य डिवाइस पर डेल्टा/अंतर (उदा। एक जीएनयू डिफ-पैच) भेजना चाहता है।एक स्ट्रिंग/फ़ाइल

Time = 0 
Server: has version_1 of Xml file (~800 kiB) 
Client: has version_1 of Xml file (~800 kiB) 

Time = 1 
Server: has version_1 and version_2 of Xml file (each ~800 kiB) 
     computes delta of these versions (=patch) (~10 kiB) 
     sends patch to Client (~10 kiB transferred) 

Client: computes version_2 from version_1 and patch <= this is the problem => 

वहाँ एक रूबी पुस्तकालय है कि फ़ाइलें/तार करने के लिए एक पाठ पैच लागू करने के लिए इस अंतिम चरण के कुछ कर सकते हैं:

यह योजना है? पुस्तकालय द्वारा आवश्यक पैच को स्वरूपित किया जा सकता है।

आपकी मदद के लिए धन्यवाद!

(मैं रोड्स पार मंच फ्रेमवर्क, जो प्रोग्रामिंग भाषा के रूप में रूबी का उपयोग करता है का उपयोग कर रहा हूँ।)

+0

मेरे पास पैच फ़ाइल प्रारूप पर पूर्ण नियंत्रण है। सर्वर जावा/लिनक्स चलाता है, इसलिए बहुत मानक विकल्प होना चाहिए, और मैं प्रारूप में भी कुछ भी समायोजित कर सकता हूं जो उपयोगी होगा। –

उत्तर

6

आपका पहला काम एक पैच प्रारूप चुनने के लिए है। मनुष्यों को पढ़ने के लिए सबसे कठिन प्रारूप (आईएमएचओ) लागू करने के लिए सॉफ्टवेयर का सबसे आसान प्रारूप साबित होता है: ed (1) स्क्रिप्ट। पैच उत्पन्न करने के लिए आप एक सरल /usr/bin/diff -e old.xml new.xml से शुरू कर सकते हैं; diff (1) लाइन उन्मुख पैच का उत्पादन करेगा लेकिन यह शुरू करने के लिए ठीक होना चाहिए। एड प्रारूप इस तरह दिखता है:

36a 
    <tr><td class="eg" style="background: #182349;">&nbsp;</td><td><tt>#182349</tt></td></tr> 
. 
34c 
    <tr><td class="eg" style="background: #66ccff;">&nbsp;</td><td><tt>#xxxxxx</tt></td></tr> 
. 
20,23d 

संख्याएं लाइन संख्याएं हैं, लाइन संख्या श्रेणियां अल्पविराम से अलग हैं।

  • एक: इस स्थिति में पाठ की अगली खंड जोड़ें तो फिर वहाँ तीन सिंगल पत्र आदेशों हैं।
  • सी: इस स्थिति में टेक्स्ट को निम्न ब्लॉक में बदलें। यह डी के बराबर है, इसके बाद कमांड के बराबर है।
  • डी: इन पंक्तियों को हटाएं।

आप यह भी देखेंगे कि पैच में लाइन नंबर नीचे से नीचे जाते हैं, इसलिए आपको पैच के बाद के हिस्सों में रेखा संख्याओं को गड़बड़ करने के बारे में चिंता करने की आवश्यकता नहीं है। टेक्स्ट को जोड़ने या बदलने के वास्तविक भाग को एक ही अवधि के साथ लाइन द्वारा समाप्त लाइनों के अनुक्रम के रूप में आदेशों का पालन करें (यानी /^\.$/ या patch_line == '.' आपकी वरीयता के आधार पर)। सारांश में, प्रारूप इस तरह दिखता है:

[line-number-range][command] 
[optional-argument-lines...] 
[dot-terminator-if-there-are-arguments] 

तो, एक एड पैच लागू करने, तुम सब करने की जरूरत है एक सरणी (प्रति पंक्ति एक तत्व) में लक्ष्य फ़ाइल लोड है, का उपयोग कर पैच पार्स एक साधारण राज्य मशीन, उन्हें हटाने के लिए नई लाइनें और Array#delete_at जोड़ने के लिए Array#insert पर कॉल करें। पैचर लिखने के लिए रूबी की दो दर्जन से अधिक लाइनें नहीं लेनी चाहिए और पुस्तकालय की आवश्यकता नहीं है।

आप इस तरह बाहर आने के लिए अपने XML की व्यवस्था कर सकते हैं:

<tag> 
blah blah 
</tag> 
<other-tag x="y"> 
mumble mumble 
</other> 

बजाय:

<tag>blah blah</tag><other-tag x="y">mumble mumble</other> 

तो ऊपर सरल रेखा-उन्मुख दृष्टिकोण से कार्य करेंगे; अतिरिक्त ईओएल को ज्यादा जगह नहीं लगनी पड़ेगी ताकि शुरू करने के लिए आसान कार्यान्वयन के लिए जाएं।

दो सरणी (Google "रूबी एल्गोरिदम :: diff" शुरू करने के लिए भिन्नता के उत्पादन के लिए रूबी पुस्तकालय हैं)। एक एक्सएमएल पार्सर के साथ एक diff लाइब्रेरी का संयोजन आपको पैच का उत्पादन करने देगा जो लाइन-आधारित के बजाय टैग-आधारित हैं और यह आपको बेहतर तरीके से अनुकूल कर सकता है। एक बार जब आप एड प्रारूप (और नीचे से ऊपर तक काम कर रहे पैच के ज्ञान का एहसास) चुनते हैं तो पैच प्रारूपों की पसंद महत्वपूर्ण बात है, तो बाकी सब कुछ बहुत कम प्रयास के साथ जगह में आता है।

+0

महान स्पष्टीकरण के लिए धन्यवाद। मैंने पहले ही सोचा था कि कुछ भी तैयार नहीं होगा क्योंकि Google ने कुछ भी प्रासंगिक नहीं किया है। तो मेरा अन्य खुला प्रश्न यह था कि क्या करना है और कौन सा दृढ़ चुनना है और मैं आपके सुझावों से पूरी तरह से सहमत हूं। एक बार फिर धन्यवाद। –

2

मुझे पता है कि यह प्रश्न लगभग पांच वर्ष पुराना है, लेकिन मैं वैसे भी एक उत्तर पोस्ट करने जा रहा हूं। रुबी में तारों के लिए पैच बनाने और लागू करने के लिए खोज करते समय, अब भी, मैं इस सवाल का संतोषजनक रूप से उत्तर देने वाले किसी भी संसाधन को खोजने में असमर्थ था। इसी कारण से, मैं दिखाऊंगा कि मैंने अपने आवेदन में इस समस्या को कैसे हल किया।

बनाना पैच

मैं यह सोचते करती हूं कि आप लिनक्स का उपयोग कर रहे है, वरना Cygwin के माध्यम से कार्यक्रम diff की पहुंच है। उस मामले में, आप ed script पैच बनाने के लिए उत्कृष्ट Diffy मणि का उपयोग कर सकते हैं:

patch_text = Diffy::Diff.new(old_text, new_text, :diff => "-e").to_s 

पैच

लागू करने पैच लागू करने में काफी के रूप में सरल नहीं है। मैंने अपना खुद का एल्गोरिदम लिखने का विकल्प चुना, ask for improvements in Code Review, और अंत में नीचे दिए गए कोड का उपयोग करने पर व्यवस्थित करें। यह कोड 200_success's answer के समान है, इसकी एक सुधार को सुधारने के लिए एक बदलाव को छोड़कर।

require 'stringio' 
def self.apply_patch(old_text, patch) 
    text = old_text.split("\n") 
    patch = StringIO.new(patch) 
    current_line = 1 

    while patch_line = patch.gets 
    # Grab the command 
    m = %r{\A(?:(\d+))?(?:,(\d+))?([acd]|s/\.//)\Z}.match(patch_line) 
    raise ArgumentError.new("Invalid ed command: #{patch_line.chomp}") if m.nil? 
    first_line = (m[1] || current_line).to_i 
    last_line = (m[2] || first_line).to_i 
    command = m[3] 

    case command 
    when "s/.//" 
     (first_line..last_line).each { |i| text[i - 1].sub!(/./, '') } 
    else 
     if ['d', 'c'].include?(command) 
     text[first_line - 1 .. last_line - 1] = [] 
     end 
     if ['a', 'c'].include?(command) 
     current_line = first_line - (command=='a' ? 0 : 1) # Adds are 0-indexed, but Changes and Deletes are 1-indexed 
     while (patch_line = patch.gets) && (patch_line.chomp! != '.') && (patch_line != '.') 
      text.insert(current_line, patch_line) 
      current_line += 1 
     end 
     end 
    end 
    end 
    text.join("\n") 
end 
+0

नोटिस: यदि पैच को अंतिम '।' के बाद '\ n' के बिना सहेजा जाता है, तो 'patch_line.chomp!' अंतिम '।' के लिए' nil' देता है। और अंतिम ऑपरेशन तोड़ता है। – Inversion

+0

अच्छा पकड़, @Inversion। मैंने इसे ध्यान में रखने के लिए कोड को संशोधित किया है। – user24786