очевидная ошибка разбора с «ZeroOrMore» - PullRequest
0 голосов
/ 04 июня 2018

Я использую pyparsing с python 3.6.5 на Mac.Следующий код вылетает при втором разборе:

from pyparsing import *

a = Word(alphas) + Literal(';')
b = Word(alphas) + Optional(Literal(';'))
bad_parser = ZeroOrMore(a) + b

b.parseString('hello;')
print("no problems yet...")
bad_parser.parseString('hello;')
print("this will not print because we're dead")

Это логическое поведение?Или это ошибка?


РЕДАКТИРОВАТЬ: Вот полный вывод консоли:

no problems yet...
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    bad_parser.parseString('hello;')
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pyparsing.py", line 1632, in parseString
    raise exc
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pyparsing.py", line 1622, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pyparsing.py", line 1379, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pyparsing.py", line 3395, in parseImpl
    loc, exprtokens = e._parse( instring, loc, doActions )
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pyparsing.py", line 1379, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pyparsing.py", line 2689, in parseImpl
    raise ParseException(instring, loc, self.errmsg, self)
pyparsing.ParseException: Expected W:(ABCD...) (at char 6), (line:1, col:7)

1 Ответ

0 голосов
/ 05 июня 2018

Это ожидаемое поведение.Pyparsing не делает никаких заглядываний вперед, но является чисто слева направо.Вы можете добавить в свой синтаксический анализ заглядывание вперед, но это то, что вы должны сделать для себя.

Вы можете получить более подробную информацию о том, что происходит, если включите отладку для aи b:

a.setName('a').setDebug()
b.setName('b').setDebug()

, который покажет вам, что каждый раз, когда pyparsing собирается соответствовать выражению, а затем, если совпадение не удалось или получилось успешно, и если оно прошло успешно, соответствующие токены:

Match a at loc 0(1,1)
Matched a -> ['hello', ';']
Match a at loc 6(1,7)
Exception raised:Expected W:(ABCD...) (at char 6), (line:1, col:7)
Match b at loc 6(1,7)
Exception raised:Expected W:(ABCD...) (at char 6), (line:1, col:7)

Поскольку a соответствует полной входной строке, это соответствует критерию «ноль или более».Затем pyparsing переходит к совпадению b, но так как слово и точка с запятой уже прочитаны, анализировать больше не нужно.Поскольку b не является обязательным, pyparsing вызывает исключение, которое не может быть найдено.Даже если вы проанализируете "hello; hello; hello;", все строки и полуфабрикаты будут использованы ZeroOrMore без завершающего b оставленного для анализа.

Попробуйте это:

not_so_bad_parser = ZeroOrMore(a + ~StringEnd()) + b

Утверждая, что вы хотите прочитать только a выражения, которые не находятся в конце строки, а затем проанализировать "hello;"не будет соответствовать a, и поэтому перейдите к b, который затем соответствует.

Это настолько распространенная проблема, что я добавил ключевое слово stopOn в конструкторы классов ZeroOrMore и OneOrMore, чтобы избежатьнужно добавить оверт ~ (имеется в виду NotAny).Сначала я подумал, что это может сработать:

even_less_bad_parser = ZeroOrMore(a, stopOn=b) + b

Но потом, поскольку b также соответствует a, это будет никогда совпадать с a с, иможет оставить бесподобный текст.Нам нужно останавливаться на b только в том случае, если в конце строки:

even_less_bad_parser = ZeroOrMore(a, stopOn=b + StringEnd()) + b

Я не уверен, действительно ли это удовлетворит вашу концепцию "менее плохого" состояния, но именно поэтомуpyparsing ведет себя так, как он для вас.

...