I am working with Ruby every day, but i have an issue in Python. I was found this languages very similar... But I have some problems with migration from Ruby :)
Please, help me to convert this action in python:
string = "qwerty2012"
(var, some_var, another_var) = string.unpack("a1a4a*")
this should return three variables with unpacked values from string:
var = "q" # a1
some_var = "wert" # a4
another_var = "y2012" # a*
Help me to represent it in Python Thank you!
s = "qwerty2012"
(a, b, c) = s[:1], s[1:5], s[5:]
Python does have a similar module named struct . It lacks the ability to grab the rest of the string in the same way that Ruby and PHP lifted from Perl . You can almost get there though:
>>> import struct
>>> s = 'qwerty2012'
>>> struct.unpack_from('1s4s', s)
('q', 'wert')
>>> def my_unpack(format, packed_string):
... result = []
... result.extend(struct.unpack_from(format, packed_string))
... chars_gobbled = struct.calcsize(format)
... rest = packed_string[chars_gobbled:]
... if rest:
... result.append(rest)
... return result
...
>>> my_unpack('1s4s', 'qwerty2012')
['q', 'wert', 'y2012']
>>> my_unpack('1s4s', 'qwert')
['q', 'wert']
>>> [hex(x) for x in my_unpack('<I', '\xDE\xAD\xBE\xEF')]
['0xefbeadde']
I wish that the struct
module implemented the rest of Perl's unpack
and pack
since they were incredibly useful functions for ripping apart binary packets but alas.
s = "qwerty2012"
var, some_var, another_var = s[:1], s[1:5], s[5:]
will do the assignment and yield respectively:
q
wert
y2012
The above assignment makes use of slice notation as described by the Python Docs . This SO post Good Primer for Python Slice Notation gives a good explanation too.
Here's a preliminary recreation of unpack
:
import re
import StringIO
def unpack(s, fmt):
fs = StringIO.StringIO(s)
res = []
for do,num in unpack.pattern.findall(fmt):
if num == '*':
num = len(s)
elif num == '':
num = 1
else:
num = int(num)
this = unpack.types[do](num, fs)
if this is not None:
res.append(this)
return res
unpack.types = {
'@': lambda n,s: s.seek(n), # skip to offset
'a': lambda n,s: s.read(n), # string
'A': lambda n,s: s.read(n).rstrip(), # string, right-trimmed
'b': lambda n,s: bin(reduce(lambda x,y:256*x+ord(y), s.read(n), 0))[2:].zfill(8*n)[::-1], # binary, LSB first
'B': lambda n,s: bin(reduce(lambda x,y:256*x+ord(y), s.read(n), 0))[2:].zfill(8*n) # binary, MSB first
}
unpack.pattern = re.compile(r'([a-zA-Z@](?:_|!|<|>|!<|!>|0|))(\d+|\*|)')
It works for your given example,
unpack("qwerty2012", "a1a4a*") # -> ['q', 'wert', 'y2012']
but has a long list of datatypes not yet implemented (see the documentation ).
This might ease your migration from Ruby:
import re
import struct
def unpack(format, a_string):
pattern = r'''a(\*|\d+)\s*'''
widths = [int(w) if w is not '*' else 0 for w in re.findall(pattern, format)]
if not widths[-1]: widths[-1] = len(a_string) - sum(widths)
fmt = ''.join('%ds' % f for f in widths)
return struct.unpack_from(fmt, a_string)
(var, some_var, another_var) = unpack('a1a4a*', 'qwerty2012') # also 'a1 a4 a*' OK
print (var, some_var, another_var)
Output:
('q', 'wert', 'y2012')
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.