2013-11-16 2 views
1

Я пытаюсь реализовать простой общий синтаксический анализатор RTF с pyparsing. Но теперь я застрял в странной ошибке:Parsing RTF с pyparsing

#Code: 
    control_codes = Word('\\;*' + alphanums) 
    start = Word('{') 
    end = Word('}') | (Word(';') + Word('}')) 
    header = OneOrMore(control_codes | Word(alphanums)) 

    document = Forward() 
    document <<= (
     start + 
     header + 
     (document + end) | end 
    ) 
    print document.parseString('{\\*\\falt Times New Roman}') 

    #Error 
    pyparsing.ParseException: Expected W:(}) (at char 25), (line:1, col:26) 

Char 25 is '}', это последний символ в строке. Простейший пример: более сложные примеры, которые я пытался использовать, были отрезаны частью входной строки.

ответ

1

У вас на самом деле есть ряд ошибок в этом фрагменте, и вы можете захотеть пересмотреть некоторые из документов pyparsing, чтобы убедиться, что у вас есть основы.

Word(stringOfChars) будет соответствовать группе символов, которые существуют в данном stringOfChars. Word(alphanums) будет соответствовать «ABC», «slkjfljlsdflsdjf», «2330098324», «392084lsfd0238» и так далее. Таким образом, Word("{") будет соответствовать не только «{», но также «{{« и »{{{{{{{{" - в некоторых из этих мест, где вы определяете знаки препинания, я думаю, что вы скорее всего будете использовать Literal, не Word. Literal будет соответствовать только точной строке, используемой в его конструкторе, без явного повторения.

Word(string1, string2) будет соответствовать группе символов, которые начинаются с одного из символов в string1, а затем сразу с 0 или более символов в string2. В вашем определении controlCodes, я думаю, вы хотите принять только ведущий символ '\', за которым следует 1 или более alphanums, '*' или ';'. Это было бы правильно написано как Word('\\', alphanums+'*'+';')

Поскольку вы анализируете RTF, который часто включает символы '\', вы будете делать прогресс быстрее, если будете использовать строковые литералы Python, которые позволят вам вводить строки, содержащие обратную косую черту, без необходимости их удвоения вверх. Сравнить

print document.parseString('{\\*\\falt Times New Roman}') 

и

print document.parseString(r'{\*\falt Times New Roman}') 

Единственная загвоздка в том, что вам все равно придется удвоить косую черту, если это последний (или единственный) символ в строке.

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

header.setName("header") 
header.setDebug() 

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

Match header at loc 1(1,2) 
Matched header -> ['\\', '*', '\\falt', 'Times', 'New', 'Roman'] 
Traceback (most recent call last): 
    File "rtf.py", line 26, in <module> 
    print document.parseString(r'{\*\falt Times New Roman}') 
    File "c:\python26\lib\site-packages\pyparsing.py", line 1041, in parseString 
    raise exc 
pyparsing.ParseException: Expected "}" (at char 1), (line:1, col:2) 

Я не думаю, что вы ожидали header, чтобы пройти весь путь, чтобы прочитать «Times New Roman».

Если вы еще не успели выставить BNF для своего анализатора, я настоятельно рекомендую вам это сделать. После того, как вы это записали, попробуйте следовать BNF через вашу тестовую строку - будьте как можно более буквальными, не делайте никаких предположений о том, где выражения OneOrMore должны останавливаться, потому что «это очевидно». Pyparsing не делает никакого взгляда, который вы не говорите ему.

+0

Благодарим вас за разъяснение. Я решил проблему в этой теме. pyparsing - это библиотека greate, как я вижу. – beatt

Смежные вопросы