有没有一种优雅的方式来使用struct和namedtuple而不是这个?
我读由记录的二进制文件,在C应该是这样的:有没有一种优雅的方式来使用struct和namedtuple而不是这个?
typedef _rec_t
{
char text[20];
unsigned char index[3];
} rec_t;
现在我能够解析与23个不同值的元组里面,但我们更希望,如果我能使用namedtuple
将前20个字节组合到text
中,并将其余三个字节组合到index
中。我怎样才能做到这一点?基本上而不是23个值的一个元组,我倾向于分别具有两个20和3值的元组,并使用“自然名称”(即通过namedtuple
)访问这些元组。
我目前对struct.unpack_from()
使用格式"20c3B"
。
注意:当我拨打parse_text
时,字符串中有许多连续记录。
我的代码(剥离下来的相关部分):
#!/usr/bin/env python
import sys
import os
import struct
from collections import namedtuple
def parse_text(data):
fmt = "20c3B"
l = len(data)
sz = struct.calcsize(fmt)
num = l/sz
if not num:
print "ERROR: no records found."
return
print "Size of record %d - number %d" % (sz, num)
#rec = namedtuple('rec', 'text index')
empty = struct.unpack_from(fmt, data)
# Loop through elements
# ...
def main():
if len(sys.argv) < 2:
print "ERROR: need to give file with texts as argument."
sys.exit(1)
s = os.path.getsize(sys.argv[1])
f = open(sys.argv[1])
try:
data = f.read(s)
parse_text(data)
finally:
f.close()
if __name__ == "__main__":
main()
根据文档:
>>> record = 'raymond \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)
>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name='raymond ', serialnum=4658, school=264, gradelevel=8)
所以你的情况
: http://docs.python.org/library/struct.html解压后场可以将它们分配给变量的或由一个名为元组包裹,结果被命名为
>>> import struct >>> from collections import namedtuple >>> data = "1"*23 >>> fmt = "20c3B" >>> Rec = namedtuple('Rec', 'text index') >>> r = Rec._make([struct.unpack_from(fmt, data)[0:20], struct.unpack_from(fmt, data)[20:]]) >>> r Rec(text=('1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'), index=(49, 49, 49)) >>>
切片解包变量可能是一个问题如果格式为
fmt = "20si"
或其他标准,我们不返回连续的字节,我们不需要这样做。>>> import struct >>> from collections import namedtuple >>> data = "1"*24 >>> fmt = "20si" >>> Rec = namedtuple('Rec', 'text index') >>> r = Rec._make(struct.unpack_from(fmt, data)) >>> r Rec(text='11111111111111111111', index=825307441) >>>
Aaah,请参阅......'_make'调用内切片的创造性使用是我错过的。谢谢一堆。我一直在跟踪文档,但没有得到如何做到这一点没有额外的变量。我会尽快接受,但不能upvote,直到午夜后(用完所有选票:))。 – 0xC0000022L 2012-07-12 22:20:58
@ 0xC0000022L没问题,虽然由于开销太大而难以分割,但是我对你的情况了解不多,这是我能想到的最好的情况。 – 2012-07-12 22:25:45
我们真的打算使用'_make'吗?这个领先的下划线是可疑的... – 2012-07-12 23:12:47
为什么不parse_Text在使用字符串的切片(数据[20],数据[20:])拉开两值,然后用struct来处理每一个?
或取23个值并将它们分成两部分?
我必须缺少一些东西。也许你希望通过结构模块来实现这一点?
+1。字符串数据就在'data'中,并且使用切片去掉两个固定长度的字符串是微不足道的;不需要使用'struct.unpack_from()'从字符串中获取字符串。 'struct'对于解压整数值和浮点值非常有价值,但在这里我们只有字符串。 – steveha 2012-07-12 22:01:44
@steveha:即使我想使用'offset',我不需要'unpack_from'?请记住,这是我缩小的一个例子。 – 0xC0000022L 2012-07-12 22:13:12
@ user1277476:该字符串包含'num'记录(请参阅代码)。这就是为什么我首先使用'unpack_from'的原因。当然切片也可以。谢谢。 – 0xC0000022L 2012-07-12 22:14:59
这是我的答案。我首先使用分片而不是struct.unpack()
来写它,但是@ samy.vilar指出我们可以使用“s”格式来实际得到字符串。 (我应该记住的!)
本答案使用两次:struct.unpack()
两次:一次获取字符串,一次将第二个字符串解压为整数。
我不知道你想用"3B"
项目做什么,但我猜你想要将它解开为24位整数。我在3字符串的末尾附加了一个0字节,并将其解压为一个整数,以防万一您想要。
有点棘手:像n, = struct.unpack(...)
这样的行将长度为1的元组解包为一个变量。在Python中,逗号使用元组,所以在一个名字之后用一个逗号,我们使用元组拆包将长度为1的元组拆分为单个变量。
此外,我们可以使用with
来打开文件,从而无需使用try
块。我们也可以使用f.read()
来一次读取整个文件,而不需要计算文件的大小。
def parse_text(data):
fmt = "20s3s"
l = len(data)
sz = struct.calcsize(fmt)
if l % sz != 0:
print("ERROR: input data not a multiple of record size")
num_records = l/sz
if not num_records:
print "ERROR: zero-length input file."
return
ofs = 0
while ofs < l:
s, x = struct.unpack(fmt, data[ofs:ofs+sz])
# x is a length-3 string; we can append a 0 byte and unpack as a 32-bit integer
n, = struct.unpack(">I", chr(0) + x) # unpack 24-bit Big Endian int
ofs += sz
... # do something with s and with n or x
def main():
if len(sys.argv) != 2:
print("Usage: program_name <input_file_name>")
sys.exit(1)
_, in_fname = sys.argv
with open(in_fname) as f:
data = f.read()
parse_text(data)
if __name__ == "__main__":
main()
谢谢,这个答案有一些概念,我在书中学习(学习Python ),但还没有太多使用我自己。 – 0xC0000022L 2012-07-13 12:13:26
再次感谢。这个解决方案非常出色,特别是解码整数的部分。感谢那。由于我的问题不同(部分原因是缺乏知识),我认为这是不公平的,接受这个答案。但是,我积极筛选了一些其他与Python相关的答案,并花费了我的每日投票限额。再次感谢! – 0xC0000022L 2012-07-13 14:50:28
不客气! :-) – steveha 2012-07-13 18:49:16
'data = str()'(在'main'中)是不必要的。 – mgilson 2012-07-12 21:57:08
@mgilson:谢谢:) – 0xC0000022L 2012-07-12 22:11:48