Парсер Bencode “” в Python 3


BencodeObject класс:

деф __инит__(самостоятельная,именем): с Open(имя_файла, "РБ") в качестве diskbytes: самовывоз.нагрузок(diskbytes) деф _isdictionary(самовыдвижение,биты): возвращение(бит == б"д") деф _isnumber(самовыдвижение,биты): возвращение(бит > Б"/" и биты <б":") деф _iscolon(самовыдвижение,биты): возвращение(бит == б":") деф _isint(самовыдвижение,биты): возвращение(бит == б"я") деф _islist(самовыдвижение,биты): возвращение(бит == б"л") деф _isend(самовыдвижение,биты): возвращение(бит == В"Е") деф _isnull(самовыдвижение,биты): возвращение(бит == б"") физ нагрузок(самообслуживание,bcbuffer): жетоны = [] нуль = б"" numbuffer = значение null # буфер для хранения количество байт последний = [] в то время как правда: атом = bcbuffer.читать(1) если самостоятельно._isdictionary(атом): последние.добавить(атом) Элиф самостоятельно._isnumber(атом): numbuffer += атом Элиф самостоятельно._iscolon(атом): лексем.присоеденить(bcbuffer.читать(инт(numbuffer))) numbuffer = нуль Элиф самостоятельно._isint(атом): последние.добавить(атом) Элиф самостоятельно._islist(атом): последние.добавить(атом) Элиф самостоятельно._isend(атом): Чара = последний.поп() если самостоятельно._isint(Чара): лексем.добавить(тип int(numbuffer)) numbuffer = нуль другое: перерыв самовывоз.bytestrings = маркеры самовывоз.ул. trackerURL = (самовыдвижение.bytestrings[1],"утф-8")

Ищу любой вход можно сделать.



756
3
задан 2 ноября 2011 в 06:11 Источник Поделиться
Комментарии
1 ответ

class BencodeObject:

Ввод объектов в имена классов, как правило, не хорошая идея, потому что он мне ничего не рассказывает.

def __init__(self,filename):
with open(filename,'rb') as diskbytes:
self.loads(diskbytes)

def _isdictionary(self,bits): return(bits == b"d")

Нет необходимости для скобок вокруг выражения. Они только засоряют все

def _isnumber(self,bits): return(bits > b"/" and bits < b":")

Это запутанный способ выразить это. Вместо того чтобы использовать биты >= б'0', а бит <= '9'

def _iscolon(self,bits): return(bits == b":")
def _isint(self,bits): return(bits == b"i")
def _islist(self,bits): return(bits == b"l")
def _isend(self,bits): return(bits == b"e")
def _isnull(self,bits): return(bits == b"")

Его не ясно, насколько полезны эти функции. Ты называешь их один раз, и называя их не меньше, а затем просто проверить строку на равенство в первую очередь. Также руководство стиль питоны рекомендует использовать underscores_to_seperate_words. Как я послал, как я посылаю.

def loads(self,bcbuffer):
tokens = []
null = b""
numbuffer = null # a buffer for storing number bytes

Я не уверен, что постоянная на пустую строку необходимо. Если вы настаиваете, я предлагаю это должно быть глобальной константы.

    last = []

Последнее предполагает, ну, в прошлом. Но это больше из стека. Я думаю, что это могло быть лучшего названия

    while True:
atom = bcbuffer.read(1)
if self._isdictionary(atom): last.append(atom)

Смешивая между собой на одной линии, и на следующие строки в строку, если-elifs выглядит некрасиво и делает это тяжелее, чтобы читать. Я вообще не любитель положив тело на той же строке, что если выражение. Но он действительно не работает, когда вы смешиваете оба стиля.

        elif self._isnumber(atom): 
numbuffer += atom
elif self._iscolon(atom):
tokens.append(bcbuffer.read(int(numbuffer)))
numbuffer = null
elif self._isint(atom): last.append(atom)
elif self._islist(atom): last.append(atom)

Вы последние.добавить(атом) много. Учитывать или объединять условия

        elif self._isend(atom): 
char = last.pop()
if self._isint(char):
tokens.append(int(numbuffer))
numbuffer = null
else: break

Вы не различаете находить недопустимые символы и конец файла. В обоих случаях можно просто уйти. Я рекомендовал бы бросать исключение, если вы обнаружили недопустимый символ.

    self.bytestrings = tokens

Но маркеры также относятся цифры. Так что хранение их в bytestrings это как-то странно.

    self.trackerURL = str(self.bytestrings[1],"utf-8")

Ваш цикл соответствует общей схеме построения структур данных за несколько итераций цикла, а затем уничтожать их. Не делай этого. Он заканчивает тем, что трудно следовать логике функции, потому что я должен выяснить, что происходит за несколько итераций цикла. Вместо этого, каждой итерации цикла должны справиться с логической единицей.

Вот как я бы подойти к проблеме:

def read_number(bcbuffer, terminator):
read_byte = lambda: bcbuffer.read(1)
bytes_iter = iter(read_byte, terminator)
text = ''.join(bytes_iter)
return int(text)

def parse_tokens(self, bcbuffer):
tokens = []

while True:
atom = bcbuffer.read()
if atom == b'i':
tokens.append( read_number(bcbuffer, b'e') )
elif atom >= b'0' and atom <= b'9':
length = read_number(bcbuffer, b':')
tokens.append( bcbuffer.read(length) )
elif atom in b"lde":
pass # ignore the structure which we don't care about
elif atom == b'':
break
else:
raise IOError('Did not expect %s' % atom)

return tokens

Обратите внимание, что у меня нет коллекции переменные для хранения частичного результата. Потому что в каждой итерации цикла обработки одного "маркера" мне не нужно сохранять данные другие то, мой результат через итерации. Это также намного чище, я думаю, что происходит в анализе.

Я не проверял этот код в любом случае, использовать на свой страх и риск. Я проигнорировал возможность недействительными bencodes. read_number будет в конечном итоге в бесконечный цикл, если он не может найти символ. не-цифр до Терминатора вызовет инт кинуть ValueError. Различные методы для обработки этих существует. Я бы, наверное, обернуть файл.прочитать() бросать исключение при попытке чтения за концом файла.

3
ответ дан 2 ноября 2011 в 02:11 Источник Поделиться