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 WebView内容不同屏幕兼容处理

    最近团队里项目开发APP时,其中有个界面要用到WebView来显示,而不用原生的控件. 开发这个界面的时候遇到一个问题,就是Android的碎片化导致有众多屏幕分辨率,不同分辨率的屏幕对这个界面Web ...

  2. [JS]_proto_和prototype到底有啥区别

    是时候拿出我珍藏多年的这张图了: 首先,要明确几个点: 1.在JS里,万物皆对象.方法(Function)是对象,方法的原型(Function.prototype)是对象.因此,它们都会具有对象共有的 ...

  3. Entity Framewor 学习笔记 (include + where)

    如果我们想在子查询做过滤的话应该怎样写呢? IEnumerable<Product> products = db.products.Include(p => p.colors.Whe ...

  4. 磁盘IO单线程顺序写时最快的,如果多线程写,磁盘的磁头要不断重新寻址,所以写入速度反而会慢

    (1) 读写最好还是不要多线程,硬盘读写的速度有限,单线程时已经满负荷了,多线程又会增加线程之间的切换,会增加时间. 如果想增加读写速度,应该增加硬盘,做raid (2)首先是硬盘的写入是串行的,CP ...

  5. 笔记:java并发实践2

    public interface Executor { void execute(Runnable command); } 虽然Executor是一个简单的接口,但它为灵活且强大的异步任务框架提供了基 ...

  6. Java编程思想-第四章练习题

    练习1:写一个程序,打印从1到100的值 public class Print1To100{ public static void main(String args[]){ for(int i = 1 ...

  7. HRBUST 1987 逃课的孩子

    Sol:HASH + 二分  字符串处理,很基础的操作. 题意很明确就是找重复的次数统计下,范围比较大1≤n≤10000,1≤m≤10000. #include <cstdio> #inc ...

  8. bui上手体验

    在最近的项目中,接触到了bui这个后台管理框架 主页地址:http://builive.com/ 主页上也有一个后台管理的Demo:http://builive.com/apps/default/ma ...

  9. (ubuntu)在andorid andk工程中使用ccache加速编译速度

    环境 系统:Linux luogw-pc 3.5.0-36-generic #57~precise1-Ubuntu SMP Thu Jun 20 18:21:09 UTC 2013 x86_64 x8 ...

  10. nexus4/5/6/7/9/10设备谷歌安卓5.1.1系统底包下载

    https://developers.google.com/android/nexus/images http://www.inexus.co/thread-18488-1-1.html