The Basics

Fields

Fields are the most fundamental unit of construction: they parse (read data from the stream and return an object) and build (take an object and write it down onto a stream). There are many kinds of fields, each working with a different type of data (numeric, boolean, strings, etc.).

Some examples of parsing:

>>> from construct import UBInt16, ULInt16
>>> UBInt16("foo").parse("\x01\x02")
258
>>> ULInt16("foo").parse("\x01\x02")
513

Some examples of building:

>>> from construct import UBInt16, SBInt16
>>> UBInt16("foo").build(31337)
'zi'
>>> SBInt16("foo").build(-31337)
'\x86\x97'

Structs

For those of you familiar with C, Structs are very intuitive, but here’s a short explanation for the larger audience. A Struct is a sequenced collection of fields or other components, that are parsed/built in that order. Note that if two or more fields of a Struct have the same name, the last field “wins”; that is, the last field’s value will be the value returned from a parse.

>>> from construct import Struct, UBInt8, SLInt16, LFloat32
>>> c = Struct("foo",
... UBInt8("a"),
... SLInt16("b"),
... LFloat32("c"),
... )
>>> c
<Struct('foo')>
>>> c.parse("\x07\x00\x01\x00\x00\x00\x01")
Container(a = 7, b = 256, c = 2.350988701644575e-038)

Containers

What is that Container object, anyway? Well, a Container is a regular Python dictionary. It provides pretty-printing and accessing items as attributes, in addition to the normal facilities of dictionaries. Let’s see more of those:

>>> x = c.parse("\x07\x00\x01\x00\x00\x00\x01")
>>> x
Container(a = 7, b = 256, c = 2.350988701644575e-038)
>>> x.a
7
>>> x.b
256
>>> print x
Container:
a = 7
b = 256
c = 2.350988701644575e-038

Building

And here is how we build Structs:

>>> # Rebuild the parsed object.
>>> c.build(x)
'\x07\x00\x01\x00\x00\x00\x01'
>>> # Mutate the parsed object and build...
>>> x.b = 5000
>>> c.build(x)
'\x07\x88\x13\x00\x00\x00\x01'
>>> # ...Or, we can create a new container.
>>> c.build(Container(a = 9, b = 1234, c = 56.78))
'\t\xd2\x04\xb8\x1ecB'

Note

Building is fully duck-typed and can be done with any object.

>>> class Foo(object): pass
...
>>> f = Foo()
>>> f.a = 1
>>> f.b = 2
>>> f.c = 3
>>> c.build(f)
'\x01\x02\x00\x00\x00@@'

Nested

Structs can be nested. Structs can contain other Structs, as well as any construct. Here’s how it’s done:

>>> c = Struct("foo",
... UBInt8("a"),
... UBInt16("b"),
... Struct("bar",
... UBInt8("a"),
... UBInt16("b"),
... )
... )
>>> x = c.parse("ABBabb")
>>> x
Container(a = 65, b = 16962, bar = Container(a = 97, b = 25186))
>>> print x
Container:
a = 65
b = 16962
bar = Container:
a = 97
b = 25186
>>> x.a
65
>>> x.bar
Container(a = 97, b = 25186)
>>> x.bar.b
25186

As you can see, Containers provide human-readable representations of the data, which is very important for large data structures.

Embedding

A Struct can be embedded into an enclosing Struct. This means all the fields of the embedded Struct will be merged into the fields of the enclosing Struct. This is useful when you want to split a big Struct into multiple parts, and then combine them all into one Struct.

>>> foo = Struct("foo",
... UBInt8("a"),
... UBInt8("b"),
... )
>>> bar = Struct("bar",
... foo, # This Struct is not embedded.
... UBInt8("c"),
... UBInt8("d"),
... )
>>> bar2= Struct("bar",
... Embed(foo), # This Struct is embedded.
... UBInt8("c"),
... UBInt8("d"),
... )
>>> bar.parse("abcd")
Container(c = 99, d = 100, foo = Container(a = 97, b = 98))
>>> bar2.parse("abcd")
Container(a = 97, b = 98, c = 99, d = 100)

See also

The Embedded() macro.

Sequences

Sequences are very similar to Structs, but operate with lists rather than containers. Sequences are less commonly used than Structs, but are very handy in certain situations. Since a list is returned in place of an attribute container, the names of the sub-constructs are not important; two constructs with the same name will not override or replace each other.

Parsing

>>> c = Sequence("foo",
... UBInt8("a"),
... UBInt16("b"),
... )
>>> c
<Sequence('foo')>
>>> c.parse("abb")
[97, 25186]

Building

>>> c.build([1,2])
'\x01\x00\x02'

Nested

>>> c = Sequence("foo",
... UBInt8("a"),
... UBInt16("b"),
... Sequence("bar",
... UBInt8("a"),
... UBInt16("b"),
... )
... )
>>> c.parse("ABBabb")
[65, 16962, [97, 25186]]

Embedded

Like Structs, Sequences are compatible with the Embed wrapper. Embedding one Sequence into another causes a merge of the parsed lists of the two Sequences.

>>> foo = Sequence("foo",
... UBInt8("a"),
... UBInt8("b"),
... )
>>> bar = Sequence("bar",
... foo, # <-- unembedded
... UBInt8("c"),
... UBInt8("d"),
... )
>>> bar2 = Sequence("bar",
... Embed(foo), # <-- embedded
... UBInt8("c"),
... UBInt8("d"),
... )
>>> bar.parse("abcd")
[[97, 98], 99, 100]
>>> bar2.parse("abcd")
[97, 98, 99, 100]

Repeaters

Repeaters, as their name suggests, repeat a given unit for a specified number of times. At this point, we’ll only cover static repeaters. Meta-repeaters will be covered in the meta-constructs tutorial.

We have four kinds of static repeaters. In fact, for those of you who wish to go under the hood, two of these repeaters are actually wrappers around Range.

construct.Range(mincountmaxcoutsubcon)

A range-array. The subcon will iterate between mincount to maxcount times. If less than mincount elements are found, raises RangeError.

See also

The GreedyRange() and OptionalGreedyRange() macros.

The general-case repeater. Repeats the given unit for at least mincount times, and up to maxcount times. If an exception occurs (EOF, validation error), the repeater exits. If less than mincount units have been successfully parsed, a RangeError is raised.

Note

This object requires a seekable stream for parsing.

Parameters:
  • mincount – the minimal count
  • maxcount – the maximal count
  • subcon – the subcon to repeat

Example:

>>> c = Range(3, 7, UBInt8("foo"))
>>> c.parse("\x01\x02")
Traceback (most recent call last):
...
construct.core.RangeError: expected 3..7, found 2
>>> c.parse("\x01\x02\x03")
[1, 2, 3]
>>> c.parse("\x01\x02\x03\x04\x05\x06")
[1, 2, 3, 4, 5, 6]
>>> c.parse("\x01\x02\x03\x04\x05\x06\x07")
[1, 2, 3, 4, 5, 6, 7]
>>> c.parse("\x01\x02\x03\x04\x05\x06\x07\x08\x09")
[1, 2, 3, 4, 5, 6, 7]
>>> c.build([1,2])
Traceback (most recent call last):
...
construct.core.RangeError: expected 3..7, found 2
>>> c.build([1,2,3,4])
'\x01\x02\x03\x04'
>>> c.build([1,2,3,4,5,6,7,8])
Traceback (most recent call last):
...
construct.core.RangeError: expected 3..7, found 8
construct.Array(countsubcon)

Repeats the given unit a fixed number of times.

Parameters:
  • count – number of times to repeat
  • subcon – construct to repeat

Example:

>>> c = Array(4, UBInt8("foo"))
>>> c.parse("\x01\x02\x03\x04")
[1, 2, 3, 4]
>>> c.parse("\x01\x02\x03\x04\x05\x06")
[1, 2, 3, 4]
>>> c.build([5,6,7,8])
'\x05\x06\x07\x08'
>>> c.build([5,6,7,8,9])
Traceback (most recent call last):
...
construct.core.RangeError: expected 4..4, found 5
construct.GreedyRange(subcon)

Repeats the given unit one or more times.

Parameters: subcon – construct to repeat

Example:

>>> from construct import GreedyRange, UBInt8
>>> c = GreedyRange(UBInt8("foo"))
>>> c.parse("\x01")
[1]
>>> c.parse("\x01\x02\x03")
[1, 2, 3]
>>> c.parse("\x01\x02\x03\x04\x05\x06")
[1, 2, 3, 4, 5, 6]
>>> c.parse("")
Traceback (most recent call last):
...
construct.core.RangeError: expected 1..2147483647, found 0
>>> c.build([1,2])
'\x01\x02'
>>> c.build([])
Traceback (most recent call last):
...
construct.core.RangeError: expected 1..2147483647, found 0
construct.OptionalGreedyRange(subcon)

Repeats the given unit zero or more times. This repeater can’t fail, as it accepts lists of any length.

Parameters: subcon – construct to repeat

Example:

>>> from construct import OptionalGreedyRange, UBInt8
>>> c = OptionalGreedyRange(UBInt8("foo"))
>>> c.parse("")
[]
>>> c.parse("\x01\x02")
[1, 2]
>>> c.build([])
''
>>> c.build([1,2])
'\x01\x02'

Nesting

As with all constructs, Repeaters can be nested too. Here’s an example:

>>> c = Array(5, Array(2, UBInt8("foo")))
>>> c.parse("aabbccddee")
[[97, 97], [98, 98], [99, 99], [100, 100], [101, 101]]
 

python construct文档的更多相关文章

  1. 如何在命令行模式下查看Python帮助文档---dir、help、__doc__

    如何在命令行模式下查看Python帮助文档---dir.help.__doc__ 1.dir函数式可以查看对象的属性,使用方法很简单,举str类型为例,在Python命令窗口输入 dir(str) 即 ...

  2. python统计文档中词频

    python统计文档中词频的小程序 python版本2.7 效果如下: 程序如下,测试文件与完整程序在我的github中 #统计空格数与单词数 本函数只返回了空格数 需要的可以自己返回多个值 def ...

  3. 在命令行模式下查看Python帮助文档---dir、help、__doc__

    在命令行模式下查看Python帮助文档---dir.help.__doc__   1.dir函数式可以查看对象的属性,使用方法很简单,举str类型为例,在Python命令窗口输入 dir(str) 即 ...

  4. Python帮助文档中Iteration iterator iterable 的理解

    iteration这个单词,是循环,迭代的意思.也就是说,一次又一次地重复做某件事,叫做iteration.所以很多语言里面,循环的循环变量叫i,就是因为这个iteration. iteration指 ...

  5. 使用Python对文档单词进行计数

    做hacker.org上面的题目时,遇到了一个题目需要对RFC3280种长度为9的单词进行计数,并找出这些单词中出现次数最多的那个:Didactic Byte RFC3280文档有7000多行,靠人工 ...

  6. 三言两语聊Python模块–文档测试模块doctest

    doctest是属于测试模块里的一种,对注释文档里的示例进行检测. 给出一个例子: splitter.pydef split(line, types=None, delimiter=None): &q ...

  7. python 本地文档查看

    本地安装Python文档本地查看,在命令行中运行: python -m pydoc -p 1234 在浏览器中访问如下链接,就可以访问到本地文档: http://localhost:1234/ 本地文 ...

  8. 使用Sphinx生成本地的Python帮助文档

    第一步:安装Sphinx 首先我们需要安装Sphinx,如果已经安装了Anaconda,那么只需要使用如下命令即可安装,关于其中的参数 -c anaconda,可以在链接[1]中查看: conda i ...

  9. Python asyncio文档阅读摘要

    文档地址:https://docs.python.org/3/library/asyncio.html 文档第一句话说得很明白,asyncio是单线程并发,这种event loop架构是很多新型异步并 ...

随机推荐

  1. android 适配器simpleadapter和baseadapter区别

    android 适配器 simpleadapter 和 baseadapter 设计网络程序或者数据处理显示程序的时候,常常会使用 simpleadapter 和baseadapter 来实现. ad ...

  2. uva10003 Cutting Sticks

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  3. Altium Designer中Via过孔设置

  4. Java JDBC中,MySQL字段类型到JAVA类型的转换

    1. 概述 在使用Java JDBC时,你是否有过这样的疑问:MySQL里的数据类型到底该选择哪种Java类型与之对应?本篇将为你揭开这个答案. 2. 类型映射  java.sql.Types定义了常 ...

  5. python手记(38)

    runfile(r'K:\testpro\testopencv.py', wdir=r'K:\testpro') http://blog.csdn.net/myhaspl myhaspl@qq.com ...

  6. git “bad index file sha1 signature fatal: index file corrupt”错误

    在执行commit或revert等操作时,提示“bad index file sha1 signature fatal: index file corrupt”错误,导致操作失败.这是由于git的in ...

  7. 设计模式(十一):FACADE外观模式 -- 结构型模式

    1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...

  8. 深入理解linux网络技术内幕读书笔记(九)--中断与网络驱动程序

    Table of Contents 1 接收到帧时通知驱动程序 1.1 轮询 1.2 中断 2 中断处理程序 3 抢占功能 4 下半部函数 4.1 内核2.4版本以后的下半部函数: 引入软IRQ 5 ...

  9. MySQL的数据库引擎的类型

    你能用的数据库引擎取决于mysql在安装的时候是如何被编译的.要添加一个新的引擎,就必须重新编译MYSQL.在缺省情况下,MYSQL支持三个引擎:ISAM.MYISAM和HEAP.另外两种类型INNO ...

  10. zepto笔记

    $.contains: 判断节点是否存在的很好方式[另一个提供类似功能的函数是has] $.grep: 过滤数组 $.type: 获取变量类型 $.closest: 返回最先匹配到的祖先元素 $.ma ...