对于我的一个项目,我正在尝试实现 BitTorrent 协议(protocol)的一小部分,可以找到 here .具体来说,我想使用它的“Bencoding”部分,这是一种安全编码数据以通过套接字传输的方法。格式如下:
8:a string => "a string"
i1234e => 1234
l1:a1:be => ['a', 'b']
d1:a1:b3:one3:twoe => {'a':'b', 'one':two}
编码部分很容易,但是解码就变得很麻烦了。例如,如果我有一个字符串列表,我无法将它们分成单独的字符串。我尝试了几种不同的解决方案,包括 PyParsing和自定义 token 解析器。我目前正在尝试使用正则表达式,它似乎进展顺利,但我仍然挂断了字符串问题。我当前的正则表达式是:
(?P<length>\d+):(?P<contents>.{\1})
但是,我似乎无法使用第一组作为第二组的长度。有什么好办法吗?还是我的做法完全错误,而答案就在我面前?
最佳答案
您为此使用的任何解析器都需要是有状态的(即记住东西),而正则表达式大体上不是有状态的。他们是这项工作的错误工具。
如果这些是您唯一需要担心的数据类型,我想我只需为每种数据类型编写自定义解析器,在读取第一个字符后将控制权传递给适当的解析器。
我现在实际上会实现一个,但已经晚了。
好吧,我决定写一个实现:
from StringIO import StringIO
import string
inputs = ["10:a stringly",
"i1234e" ,
"l1:a1:be",
"d1:a1:b3:one3:twoe"]
# Constants
DICT_TYPE = 'd'
LIST_TYPE = 'l'
INT_TYPE = 'i'
TOKEN_EOF = ''
TOKEN_END = 'e'
COLON = ':'
class BadTypeIndicatorException(Exception):pass
def read_int(stream):
s = ""
while True:
ch = stream.read(1)
if ch not in [TOKEN_EOF, TOKEN_END, COLON]:
s += ch
else:
break
return s
def tokenize(stream):
s = ""
while True:
ch = stream.read(1)
if ch == TOKEN_END or ch == TOKEN_EOF:
return
if ch == COLON:
length = int(s)
yield stream.read(length)
s = ""
else:
s += ch
def parse(stream):
TYPE = stream.read(1)
if TYPE in string.digits:
length = int( TYPE + read_int(stream) )
return stream.read(length)
elif TYPE is INT_TYPE:
return int( read_int(stream) )
elif TYPE is LIST_TYPE:
return list(tokenize(stream))
elif TYPE is DICT_TYPE:
tokens = list(tokenize(stream))
return dict(zip(tokens[0::2], tokens[1::2]))
else:
raise BadTypeIndicatorException
for input in inputs:
stream = StringIO(input)
print parse(stream)
关于python - 如何用正则表达式匹配一定长度的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/938065/