声明
本文是译文,只是为了方便自己学习,同时加强自己的英文技能。所有文章不是为了翻译而翻译,而是为了学习感兴趣的技术而翻译。
同时文章以 reStructuredText (rst) 文档发布于 https://github.com/Deteriorator/study-documents 仓库,本文链接:https://github.com/Deteriorator/study-documents/blob/master/Simple-BitTorrent-Decoder/A-Simple-BitTorrent-Decoder.rst
原文来自于 https://effbot.org/zone/bencode.htm
正文
这是一个 BitTorrent Torrent 编码格式 bencode 的简单解码器。它使用了来自于 Simple Iterator-based Parsing 基于迭代器的方法,从而产生了可读且高效的代码。
import re
def tokenize(text, match=re.compile("([idel])|(\d+):|(-?\d+)").match):
i = 0
while i < len(text):
m = match(text, i)
s = m.group(m.lastindex)
i = m.end()
if m.lastindex == 2:
yield "s"
yield text[i:i+int(s)]
i = i + int(s)
else:
yield s
def decode_item(next, token):
if token == "i":
# integer: "i" value "e"
data = int(next())
if next() != "e":
raise ValueError
elif token == "s":
# string: "s" value (virtual tokens)
data = next()
elif token == "l" or token == "d":
# container: "l" (or "d") values "e"
data = []
tok = next()
while tok != "e":
data.append(decode_item(next, tok))
tok = next()
if token == "d":
data = dict(zip(data[0::2], data[1::2]))
else:
raise ValueError
return data
def decode(text):
try:
src = tokenize(text)
data = decode_item(src.next, src.next())
for token in src: # look for more tokens
raise SyntaxError("trailing junk")
except (AttributeError, ValueError, StopIteration):
raise SyntaxError("syntax error")
return data
大多数编码对象由类型代码,对象值和结束代码组成;而例外是编码字符串,其前缀为长度。为了简化解析器,tokenize 函数将字符串作为两个“虚拟”token返回;一个类型代码,后跟着字符串值。一些例子:
>>> list(tokenize("4:spam"))
['s', 'spam']
>>> list(tokenize("i3e")) # int
['i', '3', 'e']
>>> list(tokenize("i-3e"))
['i', '-3', 'e']
>>> list(tokenize("l4:spam4:eggse")) # list
['l', 's', 'spam', 's', 'eggs', 'e']
>>> list(tokenize("d3:cow3:moo4:spam4:eggse")) # dict
['d', 's', 'cow', 's', 'moo', 's', 'spam', 's', 'eggs', 'e']
请注意,越简单的格式通常可以使用 finditer 方法进行拆分(或甚至于使用 findall )。
encode_item 函数使用类型信息将数据转换为合适的 Python 对象。 它调用自身来处理嵌套的容器类型。
使用方法
这是一个代码清单,列出了种子文件中包含的所有文件:
data = open("test.torrent", "rb").read()
torrent = decode(data)
for file in torrent["info"]["files"]:
print "%r - %d bytes" % ("/".join(file["path"]), file["length"])
运行此命令将产生类似以下内容:
'Little Earthquakes/01 Crucify.m4a' - 4845721 bytes
'Little Earthquakes/02 Girl.m4a' - 4012517 bytes
'Little Earthquakes/03 Silent All These Years.m4a' - 4076790 bytes
'Little Earthquakes/04 Precious Things.m4a' - 4328948 bytes
'Little Earthquakes/05 Winter.m4a' - 5538530 bytes
'Little Earthquakes/06 Happy Phantom.m4a' - 3204091 bytes
'Little Earthquakes/07 China.m4a' - 4859246 bytes
'Little Earthquakes/08 Leather.m4a' - 3125716 bytes
'Little Earthquakes/09 Mother.m4a' - 6785591 bytes
'Little Earthquakes/10 Tear In Your Hand.m4a' - 4515482 bytes
'Little Earthquakes/11 Me And A Gun.m4a' - 3649914 bytes
'Little Earthquakes/12 Little Earthquakes.m4a' - 6663794 bytes
结语
在最后,我需要补充一下,这篇文章的原文发布于2007.08,我用这段代码解析几个种子文件出现了错误,通过打印完整的解析结果发现有的种子中是没有files字段的,因此这段代码只是一个参考,把它转换成适合自己的才是最好的。
如有错误,敬请指出,感谢指正! —2020-09-23 21:57:50
最新评论
这个软件有bug的,客户端windows有些键不能用如逗号、句号
没有收到邮件通知
我的评论通知貌似坏掉了,定位一下问题
测试一下重新部署后的邮件功能
居然看到自己公司的MIB库,诚惶诚恐
那可能是RobotFramework-ride的版本问题。我装的1.7.4.2,有这个限制。我有空再尝试下旧版本吧,感谢回复。
你好!我在python2.7中安装RobotFramework-ride的时候提示wxPython的版本最高是2.18.12,用pip下载的wxPython版本是4.10,而且我在那个路径下没有找到2
真的太好了,太感谢了,在bilibili和CSDN上都找遍了,终于在你这里找到了