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. z-index的最大值、最小值

    浏览器 最大值 超过最大值后变成 最小值 小于最小值后变成 备注 IE6 2147483647 2147483647 -2147483648 -2147483648   IE7 2147483647 ...

  2. 禁用USB存储设备(不重启)

    Title:禁用USB存储设备(不重启) -- 2012-09-13 12:08 在win2003实验,USB存储禁止,无需重启! stop usbrw.reg ------------------- ...

  3. DBUtils框架

    一.O-R Mapping 简介    一]概念:可以理解为对象和数据库的映射.    二]常用O-R Mapping映射工具        1)Hibernate(全自动框架)        2)l ...

  4. Android百度地图默认位置中心点设置

    //初始化地图    MapView mMapView = (MapView) findViewById(R.id.map); BaiduMap mBaidumap = mMapView.getMap ...

  5. SQLiteDatabase中的事务

    beginTransaction():开始事务endTransaction():结束事务SQLiteDatabase还提供了如下方法来判断当前上下文是否处于事物环境中.inTransaction(): ...

  6. Usage、Usage Minimum和Usage Maximum项目详解

    (1)一个产生多个数据域(Report Count>1)的主项目之前有一个以上的[用途]时,每个[用途]与一个数据域依次对应,如果数据域个数(Report Count)超过[用途]的个数,则剩余 ...

  7. 【HDOJ】3316 Mine sweeping

    简单BFS. #include <iostream> #include <cstdio> #include <cstring> #include <cstdl ...

  8. 【HDOJ】1500 Chopsticks

    DP. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm ...

  9. COJ 0034 动态的数字三角形

    题解:简单dp吧. 自顶向下的写法: #include<iostream> #include<cstdio> #include<cmath> #include< ...

  10. HDU_2036——多边形面积,行列式计算

    Problem Description “ 改革春风吹满地, 不会AC没关系; 实在不行回老家, 还有一亩三分地. 谢谢!(乐队奏乐)”话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也 ...