2012-08-07 9 views
6

के साथ समाप्त होने वाली संरचना को अनपॅक करना मैं एक ASCII स्ट्रिंग के साथ समाप्त होने वाले डेटा रिकॉर्ड को अलग करने के लिए struct.unpack() का उपयोग करने का प्रयास कर रहा हूं।ASCIIZ स्ट्रिंग

रिकॉर्ड (यह एक टॉम टॉम ov2 रिकॉर्ड होता है) इस प्रारूप है (संग्रहीत थोड़ा-endian):

  • 1 बाइट कुल रिकॉर्ड आकार के लिए
  • 4 बाइट पूर्णांक (इस क्षेत्र सहित)
  • 4 बाइट पूर्णांक
  • 4 बाइट पूर्णांक
  • चर लंबाई स्ट्रिंग, अशक्त-समाप्त

unpack() आवश्यक है कि स्ट्रिंग की लंबाई आपके द्वारा पास प्रारूप में शामिल की जाए।

str_len = struct.unpack("<xi", record[:5])[0] - 13 
fmt = "<biii{0}s".format(str_len) 

तो पूर्ण unpacking के साथ आगे बढ़ना है, लेकिन स्ट्रिंग के बाद से अशक्त-समाप्त होता है: स्ट्रिंग लंबाई प्राप्त करने के लिए - 13 बाइट्स - मैं दूसरे क्षेत्र और रिकॉर्ड के बाकी के नाम से जाना जाता आकार का उपयोग कर सकते , मैं वास्तव में चाहता हूं कि unpack() मेरे लिए यह करेगी। यह भी अच्छा होगा कि मुझे यह उस संरचना में चलाना चाहिए जिसमें उसका अपना आकार शामिल न हो।

मैं यह कैसे कर सकता हूं?

+0

हालांकि मैं इस का उत्तर दिया है वहाँ स्थान या प्रारूप स्ट्रिंग में 'z' चरित्र की घटनाओं की संख्या के लिए कोई प्रतिबंध नहीं मैं जिस समाधान के साथ आया था उसे साझा करने के लिए, मुझे दूसरों को देखने में खुशी होगी। –

उत्तर

5

आकार-कम रिकॉर्ड को संभालने में काफी आसान है, वास्तव में, क्योंकि struct.calcsize() आपको वह लंबाई बताएगा जो इसकी अपेक्षा करता है। आप unpack() के लिए एक नई प्रारूप स्ट्रिंग बनाने के लिए डेटा की वास्तविक लंबाई का उपयोग कर सकते हैं जिसमें सही स्ट्रिंग लंबाई शामिल है।

इस समारोह बस unpack() के लिए एक आवरण, अंतिम स्थिति में एक नया प्रारूप चरित्र कि टर्मिनल NUL छोड़ देंगे अनुमति देता है:

import struct 
def unpack_with_final_asciiz(fmt, dat): 
    """ 
    Unpack binary data, handling a null-terminated string at the end 
    (and only at the end) automatically. 

    The first argument, fmt, is a struct.unpack() format string with the 
    following modfications: 
    If fmt's last character is 'z', the returned string will drop the NUL. 
    If it is 's' with no length, the string including NUL will be returned. 
    If it is 's' with a length, behavior is identical to normal unpack(). 
    """ 
    # Just pass on if no special behavior is required 
    if fmt[-1] not in ('z', 's') or (fmt[-1] == 's' and fmt[-2].isdigit()): 
     return struct.unpack(fmt, dat) 

    # Use format string to get size of contained string and rest of record 
    non_str_len = struct.calcsize(fmt[:-1]) 
    str_len = len(dat) - non_str_len 

    # Set up new format string 
    # If passed 'z', treat terminating NUL as a "pad byte" 
    if fmt[-1] == 'z': 
     str_fmt = "{0}sx".format(str_len - 1) 
    else: 
     str_fmt = "{0}s".format(str_len) 
    new_fmt = fmt[:-1] + str_fmt 

    return struct.unpack(new_fmt, dat) 

>>> dat = b'\x02\x1e\x00\x00\x00z\x8eJ\x00\xb1\x7f\x03\x00Down by the river\x00' 
>>> unpack_with_final_asciiz("<biiiz", dat) 
(2, 30, 4886138, 229297, b'Down by the river') 
6

मैं दो नए कार्यों बना होना चाहिए कि मानक पैक और अनपैक फ़ंक्शंस के लिए ड्रॉप-इन प्रतिस्थापन के रूप में उपयोग योग्य। वे दोनों ASCIIZ स्ट्रिंग को पैक/अनपैक करने के लिए 'z' वर्ण का समर्थन करते हैं।

import struct 

def unpack (format, buffer) : 
    while True : 
     pos = format.find ('z') 
     if pos < 0 : 
      break 
     asciiz_start = struct.calcsize (format[:pos]) 
     asciiz_len = buffer[asciiz_start:].find('\0') 
     format = '%s%dsx%s' % (format[:pos], asciiz_len, format[pos+1:]) 
    return struct.unpack (format, buffer) 

def pack (format, *args) : 
    new_format = '' 
    arg_number = 0 
    for c in format : 
     if c == 'z' : 
      new_format += '%ds' % (len(args[arg_number])+1) 
      arg_number += 1 
     else : 
      new_format += c 
      if c in 'cbB?hHiIlLqQfdspP' : 
       arg_number += 1 
    return struct.pack (new_format, *args) 

यहाँ कैसे उन्हें इस्तेमाल करने का एक उदाहरण है:

>>> from struct_z import pack, unpack 
>>> line = pack ('<izizi', 1, 'Hello', 2, ' world!', 3) 
>>> print line.encode('hex') 
0100000048656c6c6f000200000020776f726c64210003000000 
>>> print unpack ('<izizi',line) 
(1, 'Hello', 2, ' world!', 3) 
>>>