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 部分属性学习

    android:imeOptions属性 谈一下个人的理解,设置软件盘中下一个/完成按钮的显示,如果需要监听软件盘中该按钮的事件,则需要实现 setOnEditorActionListener 其实, ...

  2. Linux C判断日期格式是否合法

    Title:Linux C判断日期格式是否合法 --2013-10-11 11:54 #include <string.h> // strlen() , strncpy() #includ ...

  3. 使用dom4j生成xml字符串,以及解析xml字符串

    基于dom4j-1.6.1.jar import java.io.IOException; import java.io.StringWriter; import java.util.ArrayLis ...

  4. Android利用百度地图定位

    百度地图照着百度的教程做的总是出现报错 请帮我看看错误在那 2013-12-13 15:16168海军 | 分类:百度地图 | 浏览1252次 java.lang.RuntimeException: ...

  5. Mono Compatibility

    The easiest way to describe what Mono currently supports is:Everything in .NET 4.5 except WPF, WWF, ...

  6. IBM Cognos 10 启动报错

    报错信息: 15:35:02, 'LogService', 'StartService', 'Success'. 15:35:03, CAF input validation enabled. 15: ...

  7. 【转】ArrayList和LinkedList的几种循环遍历方式及性能对比分析

    原文网址:http://www.trinea.cn/android/arraylist-linkedlist-loop-performance/ 主要介绍ArrayList和LinkedList这两种 ...

  8. cocos2d-x游戏开发(十七)NDK+ant编译暗黑世界

    个人原创,欢迎转载http://blog.csdn.net/dawn_moon/article/details/12308967 9秒论坛的客户端暗黑世界,ios已经跑过了,今天搞了一下安卓的,记录一 ...

  9. javascript 缓冲运动demo

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. iOS打电话、发邮件、发短信、打开浏览器

    //1.调用 自带mail [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://163@16 ...