pyparsing - разобрать xml комментарий
Мне нужно проанализировать файл, содержащий комментарии XML. В частности, это AC# файл с использованием MS ///
условность.
Из этого мне нужно вытащить foobar
, или же /// foobar
было бы приемлемо тоже. (Обратите внимание - это все равно не работает, если вы делаете XML все в одной строке...)
testStr = """
///<summary>
/// foobar
///</summary>
"""
Вот что у меня есть:
import pyparsing as pp
_eol = pp.Literal("\n").suppress()
_cPoundOpenXmlComment = Suppress('///<summary>') + pp.SkipTo(_eol)
_cPoundCloseXmlComment = Suppress('///</summary>') + pp.SkipTo(_eol)
_xmlCommentTxt = ~_cPoundCloseXmlComment + pp.SkipTo(_eol)
xmlComment = _cPoundOpenXmlComment + pp.OneOrMore(_xmlCommentTxt) + _cPoundCloseXmlComment
match = xmlComment.scanString(testStr)
и вывести:
for item,start,stop in match:
for entry in item:
print(entry)
Но у меня не было большого успеха с грамматикой, работающей через многострочное.
(примечание - я тестировал приведенный выше пример в python 3.2; он работает, но (по моей проблеме) не печатает никаких значений)
Спасибо!
3 ответа
Как насчет использования nestedExpr
:
import pyparsing as pp
text = '''\
///<summary>
/// foobar
///</summary>
blah blah
///<summary> /// bar ///</summary>
///<summary> ///<summary> /// baz ///</summary> ///</summary>
'''
comment=pp.nestedExpr("///<summary>","///</summary>")
for match in comment.searchString(text):
print(match)
# [['///', 'foobar']]
# [['///', 'bar']]
# [[['///', 'baz']]]
Я думаю Literal('\n')
это твоя проблема. Вы не хотите создавать литерал с пробельными символами (поскольку литералы по умолчанию пропускают пробельные символы перед попыткой сопоставления). Попробуйте использовать LineEnd()
вместо.
РЕДАКТИРОВАТЬ 1: То, что вы получили бесконечный цикл с LineEnd, не означает, что Literal('\n') лучше. Попробуйте добавить .setDebug()
на конце вашего _eol
определение, и вы увидите, что оно никогда ничего не соответствует.
Вместо того, чтобы пытаться определить тело вашего комментария как "одну или несколько строк, которые не являются закрывающей строкой, но приводят все к концу строки", что, если вы просто сделаете:
xmlComment = _cPoundOpenXmlComment + pp.SkipTo(_cPoundCloseXmlComment) + _cPoundCloseXmlComment
(Причина, по которой вы получили бесконечный цикл с LineEnd(), заключалась в том, что вы, по сути, выполняли OneOrMore(SkipTo(LineEnd())), но никогда не использовали LineEnd(), поэтому OneOrMore просто продолжал сопоставлять и сопоставлять и сопоставлять, анализировать и возврат пустой строки, поскольку позиция разбора была в конце строки.)
Вы можете использовать синтаксический анализатор xml для анализа xml. Должно быть легко извлечь соответствующие строки комментариев:
import re
from xml.etree import cElementTree as etree
# extract all /// lines
lines = re.findall(r'^\s*///(.*)', text, re.MULTILINE)
# parse xml
root = etree.fromstring('<root>%s</root>' % ''.join(lines))
print root.findtext('summary')
# -> foobar