2012-12-05 17 views
7

मानक दस्तावेज पढ़ने के बाद भी, मैं अभी भी समझ नहीं पा रहा हूं कि रुबी के Array#pack और String#unpack बिल्कुल काम करते हैं।रूबी का पैक और अनपैक

irb(main):001:0> chars = ["61","62","63"] 
=> ["61", "62", "63"] 
irb(main):002:0> chars.pack("H*") 
=> "a" 
irb(main):003:0> chars.pack("HHH") 
=> "```" 

मैं इन दोनों के संचालन एक ही आउटपुट लौटने की उम्मीद: "abc" यहाँ उदाहरण है कि मुझे सबसे ज्यादा मुसीबत खड़ी कर रहा है। उनमें से प्रत्येक एक अलग तरीके से "विफल" होता है (वास्तव में असफल नहीं है क्योंकि मैं शायद गलत चीज़ की अपेक्षा करता हूं)। तो दो प्रश्न:

  1. उन आउटपुट के पीछे तर्क क्या है?
  2. मैं अपने इच्छित प्रभाव को कैसे प्राप्त कर सकता हूं, यानी हेक्साडेसिमल संख्याओं के अनुक्रम को इसी स्ट्रिंग में बदल रहा हूं। इससे भी बेहतर - एक पूर्णांक एन दिया गया है, इसे टेक्स्ट फ़ाइल के समान स्ट्रिंग में कैसे परिवर्तित किया जाए, जिसे किसी संख्या के रूप में माना जाता है (कहें, एक हेक्स संपादक में) n के बराबर है?
+0

' 'H'' प्रारूपों के लिए,' * 'एक उम्मीद तरीके से अभिनय नहीं कर रहा है दस्तावेज के अनुसार। अन्य प्रारूप वर्ण सही तरीके से व्यवहार करते प्रतीत होते हैं, इसलिए मुझे संदेह है कि रूबी के 'एच *' के उपयोग में यह एक बग है। –

उत्तर

10

हम आज सुबह इसी तरह की समस्या पर काम कर रहे थे। सरणी आकार अज्ञात है, तो आप उपयोग कर सकते हैं:

ary = ["61", "62", "63"] 
ary.pack('H2' * ary.size) 
=> "abc" 

आप का उपयोग कर इसे उल्टा कर सकते हैं:

str = "abc" 
str.unpack('H2' * str.size) 
=> ["61", "62", "63"] 
+1

क्या यह बड़े इनपुट के लिए सक्षम होगा? –

+0

बहुत कुशल होना चाहिए। एकमात्र अतिरिक्त लागत जो मैं देखता हूं वह अस्थायी प्रारूप स्ट्रिंग बना रहा है, जिसे 'एच *' को वैसे भी करना होगा। –

+0

यह मजाकिया है कि "एच 2 *" काम नहीं करता है। –

5

Array#pack विधि सुंदर आर्केन है। प्रश्न (2) को संबोधित करते हुए मैं ऐसा करने से काम करने के लिए अपने उदाहरण प्राप्त करने में सक्षम था:

> ["61", "62", "63"].pack("H2H2H2") 
=> "abc" 

एक ऐसी ही उदाहरण के लिए Ruby documentation देखें। इसे करने का एक और सामान्य तरीका यहां है:

["61", "62", "63"].map {|s| [s].pack("H2") }.join 

यह शायद आपकी समस्या से निपटने का सबसे प्रभावी तरीका नहीं है; मुझे संदेह है कि एक बेहतर तरीका है, लेकिन यह जानने में मदद करेगा कि आप किस प्रकार के इनपुट के साथ शुरुआत कर रहे हैं।

#pack विधि पर्ल जैसे अन्य भाषाओं के लिए आम है। यदि रूबी का दस्तावेज मदद नहीं करता है, तो आप कहीं और समान दस्तावेज़ीकरण से परामर्श ले सकते हैं।

2

मैं इन दोनों के संचालन की उम्मीद ही आउटपुट वापस जाने के लिए: "abc"।

"abc".unpack("H*") 
# => ["616263"] 

["616263"].pack("H*") 
# => "abc" 

तो, ऐसा लगता है कि रूबी एक लंबे समय से अपनी हेक्स बाइट्स की उम्मीद:

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

require 'benchmark' 

chars = ["61", "62", "63"] * 100000 

Benchmark.bmbm do |bm| 
    bm.report("join pack") do [chars.join].pack("H*") end 
    bm.report("big pack") do chars.pack("H2" * chars.size) end 
    bm.report("map pack") do chars.map{ |s| [s].pack("H2") }.join end 
end 

#     user  system  total  real 
# join pack 0.030000 0.000000 0.030000 ( 0.025558) 
# big pack 0.030000 0.000000 0.030000 ( 0.027773) 
# map pack 0.230000 0.010000 0.240000 ( 0.241117) 
3

Array#pack के लिए 'H' स्ट्रिंग निर्देश का कहना है कि सरणी सामग्री होना चाहिए:

chars = ["61", "62", "63"] 
[chars.join].pack("H*") 
# => "abc" 

यह दृष्टिकोण भी बड़े निवेश के लिए तुलनात्मक रूप से अच्छा प्रदर्शन करने लगता है: तो अपने मूल प्रश्न करने का सबसे सरल जवाब यह होगा हेक्स तारों के निबल्स के रूप में व्याख्या की गई।

पहला उदाहरण आपके द्वारा दिए गए में:

irb(main):002:0> chars.pack("H*") 
=> "a" 

आप सरणी के पहले तत्व पैक करने के लिए कह रहे हैं जैसे कि यह एक हेक्स स्ट्रिंग की निबल (आधा बाइट्स) के एक दृश्य थे: 0x61 इस मामले में 'a' ASCII चरित्र से मेल खाता है।

दूसरे उदाहरण में:

irb(main):003:0> chars.pack("HHH") 
=> "```" 

आप सरणी के 3 तत्वों पैक करने के लिए रूप में यदि वे निबल (इस मामले में उच्च हिस्सा) थे कह रहे हैं: 0x60'`' ASCII वर्ण से मेल खाती है। "ATemplateString" के लिए अनुपलब्ध '2' या '*' संशोधक के कारण निम्न भाग या दूसरा निबल (0x01) "खो जाता है"।

क्या आप की जरूरत है:

chars.pack('H*' * chars.size) 

आदेश अगर वे हेक्स तार थे के रूप में सरणी के सभी तत्वों के सभी निबल पैक करने के लिए में।

'H2' * char.size का मामला केवल ठीक काम करता है अगर सरणी तत्व 1 बाइट केवल हेक्स स्ट्रिंग का प्रतिनिधित्व कर रहे हैं।

इसका मतलब है कि chars = ["6161", "6262", "6363"] की तरह कुछ अधूरा होने जा रहा है:

2.1.5 :047 > chars = ["6161", "6262", "6363"] 
=> ["6161", "6262", "6363"] 
2.1.5 :048 > chars.pack('H2' * chars.size) 
=> "abc" 

जबकि:

2.1.5 :049 > chars.pack('H*' * chars.size) 
=> "aabbcc" 
संबंधित मुद्दे