PLY: недопустимый символ «+»

Я работаю над синтаксическим анализатором python, используя ply, и мне нужно анализировать ввод в виде:

VAR VAR1 001 
+000 000 000 000

Где код создаст переменную с именем VAR 1, а затем присвоит ей значение 0.

регулярное выражение, которое я написал для экземпляра:

t_INST = r'[\+|-]0[ ][0-9][0-9][0-9][ ][0-9][0-9][0-9][ ][0-9][0-9][0-9][ ][0-9][0-9][0-9]'

Однако при запуске моей программы PLY печатает следующее:

Illegal character '+'

Репродуктор следует:

import ply.lex as lex

tokens = ['INST']
t_INST = r'[+-]0[ ](\d{3}[ ]){3}\d{3}';
t_ignore  = ' \t'
def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)

lexer = lex.lex()

def parse(input_string):
    ret = []
    lexer.input (input_string)
    while True:
        tok = lexer.token()
        if not tok:
            break      # No more input
        ret.append((tok.type, tok.value))
    return ret

print parse("+0 000 000 000")

person Wheatley    schedule 06.04.2017    source источник
comment
Вы должны использовать \d для обозначения символов, а также использовать {} для обозначения повторяющихся последовательностей: [\+-](?:\d{3}\s?){4}   -  person Neil    schedule 07.04.2017
comment
Почему обратный слеш? Вы хотели бы этого в обычном контексте, но это не имеет смысла внутри класса символов. На самом деле, если | не является допустимым первым символом, вам, вероятно, также нужен [+-], а не [+|-].   -  person Charles Duffy    schedule 07.04.2017
comment
Кстати, было бы полезно, если бы ваш репродуктор, оставаясь как можно минимальным, был расширен до точки, где он стал бы полным и поддающимся проверке, как указано в stackoverflow.com/help/mcve. Прямо сейчас кому-то нужно проделать довольно много работы, чтобы воспроизвести ошибку.   -  person Charles Duffy    schedule 07.04.2017
comment
MVCE моего парсера pastebin.com/sDW3CdyK   -  person Wheatley    schedule 07.04.2017
comment
В рамках вопроса, пожалуйста. Или, по крайней мере, где-нибудь без рекламы (если вы используете блокировщик рекламы, вы могли не заметить, что на pastebin.com их полно); gist.github.com — хороший выбор.   -  person Charles Duffy    schedule 07.04.2017
comment
@CharlesDuffy: gist.github.com/bjornefitte/ab0651e1b490eeaa4a2a4eeb3f32a657   -  person Wheatley    schedule 07.04.2017
comment
На самом деле это не приводит к сбою при запуске (предположительно, потому, что parse() никогда не вызывается?). Чтобы быть полным и поддающимся проверке, MCVE должен фактически содержать достаточно данных, чтобы фактически вызвать сбой. . (Конечно, одна из приятных особенностей gists заключается в том, что вы можете редактировать их на месте — или проверить их с помощью git, отредактировать код в локальном редакторе и снова зафиксировать их).   -  person Charles Duffy    schedule 07.04.2017
comment
@CharlesDuffy Извините, не привык к сути ... во всяком случае. я исправил это   -  person Wheatley    schedule 07.04.2017
comment
Итак, вот простой эксперимент. Измените регулярное выражение на t_INST = r'[+-]0[ ]'; вы заметите, что это совпадает. Таким образом, проблема не в +.   -  person Charles Duffy    schedule 07.04.2017
comment
Ваши реальные данные, кстати, на самом деле не соответствуют формату, указанному в вашем комментарии. +0 000 000 000 ни в коем случае не соответствует (+|-) XXX XXX XXX XXX.   -  person Charles Duffy    schedule 07.04.2017
comment
[\+|-] является допустимым регулярным выражением. Откуда вылезает эта ошибка?   -  person    schedule 07.04.2017


Ответы (2)


Линия:

print parse("+0 000 000 000")

не соответствует заявленному формату ввода

VAR VAR1 001 
+000 000 000 000

Если фактические данные имеют ту же форму, что и +0 000 000 000, то на самом деле вам нужно:

t_INST = r'[+-]0\s(?:\d{3}\s){2}\d{3}'

...с выходом: [('INST', '+0 000 000 000')]

person Charles Duffy    schedule 06.04.2017
comment
Это своего рода регулярное выражение, которое я дал в своем ответе, используя \s для ярлыка и группы без захвата. Это больше похоже на комментарий к моему вопросу. Кроме того, вы использовали {2} и должны быть {3} - person Federico Piazza; 07.04.2017
comment
Для тестовых данных OP нет, это действительно должно быть {2}. Их комментарии вводят в заблуждение относительно фактического используемого формата данных. (Вот почему я потратил время на то, чтобы заставить их предоставить настоящего воспроизводящего устройства, вместо того, чтобы писать ответ напрямую). - person Charles Duffy; 07.04.2017

Вам не нужно экранировать + в классах символов. Вы можете использовать:

t_INST = r'[+|-]0[ ][0-9][0-9][0-9][ ][0-9][0-9][0-9][ ][0-9][0-9][0-9][ ][0-9][0-9][0-9]'
   this-----^

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

t_INST = r'[+|-]0[ ][0-9]{3}[ ][0-9]{3}[ ][0-9]{3}[ ][0-9]{3}'

Или даже:

t_INST = r'[+|-]0[ ]([0-9]{3}[ ]){3}[0-9]{3}'

Также заметил, что вы использовали [+|-], это класс символов и не работает с чередованиями, поэтому вам нужно изменить его на [+-].

Итак, окончательное регулярное выражение (с использованием \d в качестве ярлыка для [0-9]) будет таким:

t_INST = r'[+-]0[ ](\d{3}[ ]){3}\d{3}'

Кстати, ваш образец текста говорит:

+000 000 000 000

Но регулярное выражение, которое вы используете, соответствует этому:

+0 000 000 000 000

Итак, если вы хотите сопоставить данные +000 000 000 000, вам нужно изменить регулярное выражение на:

t_INST = r'[+-](\d{3}[ ]){3}\d{3}'
person Federico Piazza    schedule 06.04.2017
comment
... проблема здесь (т.е. плохое поведение, из-за которого я решил написать конкурирующий ответ, а не комментировать этот) заключается в том, что вы написали ответ, фактически не имея подлинного воспроизводителя, который мог бы создать свою проблему, и, таким образом, без гарантии того, что вы действительно знали, в чем на самом деле была проблема ОП. Даже если бы re.compile(r'[\+|-]').match('+') не сработало, я согласен, что были бы веские основания для предположений, но здесь это не так: исходный код был плохим, но (проверено!) первоначально указанных оснований. - person Charles Duffy; 07.04.2017
comment
...действительно, re.compile(r'[\+|-]0[ ][0-9][0-9][0-9][ ][0-9][0-9][0-9][ ][0-9][0-9][0-9][ ][0-9][0-9][0-9]').match('+0 000 000 000 000') возвращает совпадение. - person Charles Duffy; 07.04.2017