如何将特定长度的字符串与正则表达式匹配

2024-07-07 08:27:41 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的一个项目中,我试图实现BitTorrent协议的一小部分,可以找到here。具体地说,我想使用它的“Bencoding”部分,这是一种安全编码数据以便通过套接字传输的方法。格式如下:

8:a string => "a string"
i1234e => 1234
l1:a1:be => ['a', 'b']
d1:a1:b3:one3:twoe => {'a':'b', 'one':two}

编码部分很容易,但解码却成了一个相当麻烦的问题。例如,如果我有一个字符串列表,我无法将它们分割成单独的字符串。我尝试了几种不同的解决方案,包括PyParsing和自定义令牌解析器。我目前正在尝试使用regex,它似乎运行得相当好,但我仍然被字符串问题所困扰。我当前的regex是:

^{pr2}$

然而,我似乎不能用第一组作为第二组的长度。有什么好办法吗?或者我处理这些都错了,答案就在我面前?在


Tags: 项目方法字符串l1协议stringherea1
3条回答

你需要分两步来完成。对于这样简单的解析问题,正则表达式实际上有点过头了。我是这样做的:

def read_string(stream):
    pos = stream.index(':')
    length = int(stream[0:pos])
    string = stream[pos+1:pos+1+length]
    return string, stream[pos+1+length:]

这是一种函数式的解析方法,它返回解析的值和流的其余部分。在

对于列表,可能是:

^{pr2}$

然后定义一个read_对象来检查流的第一个字符并进行适当的分派。在

如果对字符串进行两次解析,就可以这样做。应用第一个正则表达式来获取长度。连接第二个正则表达式中的长度以形成有效表达式。在

不知道如何在python中实现,但C中的一个示例是:

string regex = "^[A-Za-z0-9_]{1," + length + "}$"

如果要将1与length匹配,则字符数可以是alphanumeric或u,其中length是根据只检索长度的前一个正则表达式确定的。在

希望这有帮助:)

为此使用的任何解析器都需要是有状态的(即记住东西),而regex基本上不是有状态的。他们不适合做这项工作。在

如果这些是您唯一需要担心的数据类型,我想我应该为每个数据类型编写自定义解析器,在读取第一个字符之后将控制权传递给相应的解析器。在

我现在真的要实施一个了,但是已经晚了。

好吧,我决定写一个实现:

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)

相关问题 更多 >