Почему pyparsing обрезает синтаксический анализ, а не вызывает исключение

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

Для согласования «что значит что» используется конфигурационный файл. Суть в том, что каждое тело пакета имеет определения. Вот некоторые примеры:

abc:16
abc:15:p
abc:15:p; по умолчанию: 14: есс

Вы указываете трех- или четырехбуквенный идентификатор, за которым следует цвет, затем количество битов (которое обычно кратно четырем, но это не гарантируется) и, необязательно, еще одно двоеточие, за которым следует буква «p», означающая, что бит выделен на четность или "ecc", что означает, что для ecc выделено два бита.

Итак, переводя это на pyparsing, это то, что у меня есть:

from pyparsing import *

abbr = Word(alphas)
internal_separator = Literal(":")
bits = Word(nums, min=1, max=2)
parity = Or([CaselessLiteral("P"), CaselessLiteral("ECC")])
separator = Literal(";")

parity_part = internal_separator + parity
statement = Group(abbr + internal_separator + bits + Optional(parity_part))

#statement_list = delimitedList(statement, delim=";")
statement_list = statement + ZeroOrMore(separator + statement)

tests = ( 
    "abc:16",
    "abc:15:p", 
    "abc:15:p; def:14:ecc",
    "abc:17:p; def:q; ghi:21:", #this one should fail!
)

for t in tests:
    try:
        print t, "->", statement_list.parseString(t)
    except Exception as e:
        print e

Когда я запускаю это, вот что я получаю:

abc:16 -> [['abc', ':', '16']]
abc:15:p -> [['abc', ':', '15', ':', 'P']]
abc:15:p; def:14:ecc -> [['abc', ':', '15', ':', 'P'], ';', ['def', ':', '14', ':', 'ECC']]
abc:17:p; def:q; ghi:21: -> [['abc', ':', '17', ':', 'P']]

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

Я также попробовал «abbr» с минимальным значением 3 и максимальным значением 4, чтобы он точно распознавал, что «: q» недействителен, но это ничего не изменило.

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

Я нашел этот вопрос (Проблема с простым синтаксическим анализом в pyparsing), который кажется скорее связано, но не дает мне ответа, который я ищу.


person Mike Sandford    schedule 28.07.2014    source источник


Ответы (1)


Я могу сказать вам, почему это так, но это ожидается от pyparsing. Вам нужно будет добавить явное StringEnd() в грамматику:

statement_list = statement + ZeroOrMore(separator + statement) + StringEnd()
person BlackJack    schedule 28.07.2014
comment
Итак, я попробовал LineEnd(), но я не понял, что это функция, поэтому я снял скобки и получил странную ошибку. Большое спасибо! - person Mike Sandford; 28.07.2014
comment
Nitpick: Это не функция, а класс, и вы должны вызвать его, чтобы создать его экземпляр. - person BlackJack; 28.07.2014
comment
Вы правы, конечно. Это был уже длинный день, так что я не так педантичен, как следовало бы. Спасибо еще раз. - person Mike Sandford; 28.07.2014
comment
В качестве альтернативы добавлению StringEnd() вы также можете указать в своем вызове parseString необязательный аргумент parseAll=True. - person PaulMcG; 28.07.2014